target-arm queue:
* implement or fix various EL3 trap behaviour for system registers * clean up the trap/undef handling of the SRS instruction * add some missing AArch64 performance monitor system registers * implement reset for the PL061 GPIO device * QOMify sd.c and the pxa2xx_mmci device * SD card emulation fixes for booting Tianocore UEFI on RPi2 * QOMify various ARM timer devices -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCAAGBQJWxeEDAAoJEDwlJe0UNgzeiqwQAJ3ljFIg3iqCdPvytx+9izc1 AMdiD2XxTcZQF/71pG64RtGn9cirCFY0aHjgJJbllP0Gv0e5a77j8ZOczMRveIIZ Ss7ndOkhbCU+OYojQ3eQunl752HAcupJmDuL1WGSncOoOvOV1lSzSNsL6gguDh2R 6cgMBzhHwcuD230/SV3FHAf6BUQGs4hH3sB1cZyQY34eyFIY1O0/DwEekrUHz98R ZuuaGp22gsMQWL8zSzL8WYU13xgcBPZ/wHGXaaclcNpKQbo9Xu+bn1iIYz93Ry5g etFnR35EbBfaWWTo6sLTJI9s0hCX4lrMx5aO3DKc3PJhLcT1KYl3fXZahZdWDYya RpnoDgOizMqWDLjt+lAP/Kq9yQ9u6ji5y9UZ7yg+fqLdsM6KPLr9GINSwk51Lao0 0KoGm+O9Lpdjpz6+FY6qh6gWYQCRtvA70mhv4qhDsiwYCj35EsT3cgvMGsfMusBr m63+TeQLdzjMal5CVh+2MmjlTofVQ7xEGMucX/qHINz4MHrfzpcnoGIKeYy5PE8h exDjuYTZHN4TFLXLJ5QaRORRLTzq2ff5YcKW7pvONTD7vPMnsTlYEYnbu/Cm9x93 HkNbu+igiz/EGp6YWYsj/WOumOXlCSwFpW3k+/OYWYAKIpZAn/QWpgZGNySEEZEN +ojHRtswq4msXk6O1InV =xYJ0 -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20160218-1' into staging target-arm queue: * implement or fix various EL3 trap behaviour for system registers * clean up the trap/undef handling of the SRS instruction * add some missing AArch64 performance monitor system registers * implement reset for the PL061 GPIO device * QOMify sd.c and the pxa2xx_mmci device * SD card emulation fixes for booting Tianocore UEFI on RPi2 * QOMify various ARM timer devices # gpg: Signature made Thu 18 Feb 2016 15:19:31 GMT using RSA key ID 14360CDE # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" # gpg: aka "Peter Maydell <pmaydell@gmail.com>" # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" * remotes/pmaydell/tags/pull-target-arm-20160218-1: (36 commits) hw/timer: QOM'ify pxa2xx_timer hw/timer: QOM'ify pl031 hw/timer: QOM'ify exynos4210_rtc hw/timer: QOM'ify exynos4210_pwm hw/timer: QOM'ify exynos4210_mct hw/timer: QOM'ify arm_timer (pass 2) hw/timer: QOM'ify arm_timer (pass 1) hw/sd: use guest error logging rather than fprintf to stderr hw/sd: model a power-up delay, as a workaround for an EDK2 bug hw/sd: implement CMD23 (SET_BLOCK_COUNT) for MMC compatibility hw/sd/pxa2xx_mmci: Add reset function hw/sd/pxa2xx_mmci: Convert to VMStateDescription hw/sd/pxa2xx_mmci: Update to use new SDBus APIs hw/sd/pxa2xx_mmci: convert to SysBusDevice object sdhci_sysbus: Create SD card device in users, not the device itself hw/sd/sdhci.c: Update to use SDBus APIs hw/sd: Add QOM bus which SD cards plug in to hw/sd/sd.c: Convert sd_reset() function into Device reset method hw/sd/sd.c: QOMify hw/sd/sdhci.c: Remove x-drive property ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
		
						commit
						dd5e38b19d
					
				@ -28,6 +28,7 @@
 | 
			
		||||
#include "hw/misc/zynq-xadc.h"
 | 
			
		||||
#include "hw/ssi/ssi.h"
 | 
			
		||||
#include "qemu/error-report.h"
 | 
			
		||||
#include "hw/sd/sd.h"
 | 
			
		||||
 | 
			
		||||
#define NUM_SPI_FLASHES 4
 | 
			
		||||
#define NUM_QSPI_FLASHES 2
 | 
			
		||||
@ -154,8 +155,10 @@ static void zynq_init(MachineState *machine)
 | 
			
		||||
    MemoryRegion *address_space_mem = get_system_memory();
 | 
			
		||||
    MemoryRegion *ext_ram = g_new(MemoryRegion, 1);
 | 
			
		||||
    MemoryRegion *ocm_ram = g_new(MemoryRegion, 1);
 | 
			
		||||
    DeviceState *dev;
 | 
			
		||||
    DeviceState *dev, *carddev;
 | 
			
		||||
    SysBusDevice *busdev;
 | 
			
		||||
    DriveInfo *di;
 | 
			
		||||
    BlockBackend *blk;
 | 
			
		||||
    qemu_irq pic[64];
 | 
			
		||||
    int n;
 | 
			
		||||
 | 
			
		||||
@ -245,11 +248,23 @@ static void zynq_init(MachineState *machine)
 | 
			
		||||
    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xE0100000);
 | 
			
		||||
    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[56-IRQ_OFFSET]);
 | 
			
		||||
 | 
			
		||||
    di = drive_get_next(IF_SD);
 | 
			
		||||
    blk = di ? blk_by_legacy_dinfo(di) : NULL;
 | 
			
		||||
    carddev = qdev_create(qdev_get_child_bus(dev, "sd-bus"), TYPE_SD_CARD);
 | 
			
		||||
    qdev_prop_set_drive(carddev, "drive", blk, &error_fatal);
 | 
			
		||||
    object_property_set_bool(OBJECT(carddev), true, "realized", &error_fatal);
 | 
			
		||||
 | 
			
		||||
    dev = qdev_create(NULL, "generic-sdhci");
 | 
			
		||||
    qdev_init_nofail(dev);
 | 
			
		||||
    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xE0101000);
 | 
			
		||||
    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[79-IRQ_OFFSET]);
 | 
			
		||||
 | 
			
		||||
    di = drive_get_next(IF_SD);
 | 
			
		||||
    blk = di ? blk_by_legacy_dinfo(di) : NULL;
 | 
			
		||||
    carddev = qdev_create(qdev_get_child_bus(dev, "sd-bus"), TYPE_SD_CARD);
 | 
			
		||||
    qdev_prop_set_drive(carddev, "drive", blk, &error_fatal);
 | 
			
		||||
    object_property_set_bool(OBJECT(carddev), true, "realized", &error_fatal);
 | 
			
		||||
 | 
			
		||||
    dev = qdev_create(NULL, TYPE_ZYNQ_XADC);
 | 
			
		||||
    qdev_init_nofail(dev);
 | 
			
		||||
    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xF8007100);
 | 
			
		||||
 | 
			
		||||
@ -59,6 +59,27 @@ static void xlnx_ep108_init(MachineState *machine)
 | 
			
		||||
 | 
			
		||||
    object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_fatal);
 | 
			
		||||
 | 
			
		||||
    /* Create and plug in the SD cards */
 | 
			
		||||
    for (i = 0; i < XLNX_ZYNQMP_NUM_SDHCI; i++) {
 | 
			
		||||
        BusState *bus;
 | 
			
		||||
        DriveInfo *di = drive_get_next(IF_SD);
 | 
			
		||||
        BlockBackend *blk = di ? blk_by_legacy_dinfo(di) : NULL;
 | 
			
		||||
        DeviceState *carddev;
 | 
			
		||||
        char *bus_name;
 | 
			
		||||
 | 
			
		||||
        bus_name = g_strdup_printf("sd-bus%d", i);
 | 
			
		||||
        bus = qdev_get_child_bus(DEVICE(&s->soc), bus_name);
 | 
			
		||||
        g_free(bus_name);
 | 
			
		||||
        if (!bus) {
 | 
			
		||||
            error_report("No SD bus found for SD card %d", i);
 | 
			
		||||
            exit(1);
 | 
			
		||||
        }
 | 
			
		||||
        carddev = qdev_create(bus, TYPE_SD_CARD);
 | 
			
		||||
        qdev_prop_set_drive(carddev, "drive", blk, &error_fatal);
 | 
			
		||||
        object_property_set_bool(OBJECT(carddev), true, "realized",
 | 
			
		||||
                                 &error_fatal);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < XLNX_ZYNQMP_NUM_SPIS; i++) {
 | 
			
		||||
        SSIBus *spi_bus;
 | 
			
		||||
        DeviceState *flash_dev;
 | 
			
		||||
 | 
			
		||||
@ -327,6 +327,8 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
 | 
			
		||||
    sysbus_connect_irq(SYS_BUS_DEVICE(&s->sata), 0, gic_spi[SATA_INTR]);
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < XLNX_ZYNQMP_NUM_SDHCI; i++) {
 | 
			
		||||
        char *bus_name;
 | 
			
		||||
 | 
			
		||||
        object_property_set_bool(OBJECT(&s->sdhci[i]), true,
 | 
			
		||||
                                 "realized", &err);
 | 
			
		||||
        if (err) {
 | 
			
		||||
@ -337,6 +339,12 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
 | 
			
		||||
                        sdhci_addr[i]);
 | 
			
		||||
        sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci[i]), 0,
 | 
			
		||||
                           gic_spi[sdhci_intr[i]]);
 | 
			
		||||
        /* Alias controller SD bus to the SoC itself */
 | 
			
		||||
        bus_name = g_strdup_printf("sd-bus%d", i);
 | 
			
		||||
        object_property_add_alias(OBJECT(s), bus_name,
 | 
			
		||||
                                  OBJECT(&s->sdhci[i]), "sd-bus",
 | 
			
		||||
                                  &error_abort);
 | 
			
		||||
        g_free(bus_name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < XLNX_ZYNQMP_NUM_SPIS; i++) {
 | 
			
		||||
 | 
			
		||||
@ -56,7 +56,6 @@ typedef struct PL061State {
 | 
			
		||||
    uint32_t slr;
 | 
			
		||||
    uint32_t den;
 | 
			
		||||
    uint32_t cr;
 | 
			
		||||
    uint32_t float_high;
 | 
			
		||||
    uint32_t amsel;
 | 
			
		||||
    qemu_irq irq;
 | 
			
		||||
    qemu_irq out[8];
 | 
			
		||||
@ -65,8 +64,8 @@ typedef struct PL061State {
 | 
			
		||||
 | 
			
		||||
static const VMStateDescription vmstate_pl061 = {
 | 
			
		||||
    .name = "pl061",
 | 
			
		||||
    .version_id = 3,
 | 
			
		||||
    .minimum_version_id = 3,
 | 
			
		||||
    .version_id = 4,
 | 
			
		||||
    .minimum_version_id = 4,
 | 
			
		||||
    .fields = (VMStateField[]) {
 | 
			
		||||
        VMSTATE_UINT32(locked, PL061State),
 | 
			
		||||
        VMSTATE_UINT32(data, PL061State),
 | 
			
		||||
@ -88,7 +87,6 @@ static const VMStateDescription vmstate_pl061 = {
 | 
			
		||||
        VMSTATE_UINT32(slr, PL061State),
 | 
			
		||||
        VMSTATE_UINT32(den, PL061State),
 | 
			
		||||
        VMSTATE_UINT32(cr, PL061State),
 | 
			
		||||
        VMSTATE_UINT32(float_high, PL061State),
 | 
			
		||||
        VMSTATE_UINT32_V(amsel, PL061State, 2),
 | 
			
		||||
        VMSTATE_END_OF_LIST()
 | 
			
		||||
    }
 | 
			
		||||
@ -282,10 +280,32 @@ static void pl061_write(void *opaque, hwaddr offset,
 | 
			
		||||
    pl061_update(s);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void pl061_reset(PL061State *s)
 | 
			
		||||
static void pl061_reset(DeviceState *dev)
 | 
			
		||||
{
 | 
			
		||||
    PL061State *s = PL061(dev);
 | 
			
		||||
 | 
			
		||||
    /* reset values from PL061 TRM, Stellaris LM3S5P31 & LM3S8962 Data Sheet */
 | 
			
		||||
    s->data = 0;
 | 
			
		||||
    s->old_out_data = 0;
 | 
			
		||||
    s->old_in_data = 0;
 | 
			
		||||
    s->dir = 0;
 | 
			
		||||
    s->isense = 0;
 | 
			
		||||
    s->ibe = 0;
 | 
			
		||||
    s->iev = 0;
 | 
			
		||||
    s->im = 0;
 | 
			
		||||
    s->istate = 0;
 | 
			
		||||
    s->afsel = 0;
 | 
			
		||||
    s->dr2r = 0xff;
 | 
			
		||||
    s->dr4r = 0;
 | 
			
		||||
    s->dr8r = 0;
 | 
			
		||||
    s->odr = 0;
 | 
			
		||||
    s->pur = 0;
 | 
			
		||||
    s->pdr = 0;
 | 
			
		||||
    s->slr = 0;
 | 
			
		||||
    s->den = 0;
 | 
			
		||||
    s->locked = 1;
 | 
			
		||||
    s->cr = 0xff;
 | 
			
		||||
    s->amsel = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void pl061_set_irq(void * opaque, int irq, int level)
 | 
			
		||||
@ -318,7 +338,7 @@ static int pl061_initfn(SysBusDevice *sbd)
 | 
			
		||||
    sysbus_init_irq(sbd, &s->irq);
 | 
			
		||||
    qdev_init_gpio_in(dev, pl061_set_irq, 8);
 | 
			
		||||
    qdev_init_gpio_out(dev, s->out, 8);
 | 
			
		||||
    pl061_reset(s);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -343,6 +363,7 @@ static void pl061_class_init(ObjectClass *klass, void *data)
 | 
			
		||||
 | 
			
		||||
    k->init = pl061_initfn;
 | 
			
		||||
    dc->vmsd = &vmstate_pl061;
 | 
			
		||||
    dc->reset = &pl061_reset;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const TypeInfo pl061_info = {
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
common-obj-$(CONFIG_PL181) += pl181.o
 | 
			
		||||
common-obj-$(CONFIG_SSI_SD) += ssi-sd.o
 | 
			
		||||
common-obj-$(CONFIG_SD) += sd.o
 | 
			
		||||
common-obj-$(CONFIG_SD) += sd.o core.o
 | 
			
		||||
common-obj-$(CONFIG_SDHCI) += sdhci.o
 | 
			
		||||
 | 
			
		||||
obj-$(CONFIG_MILKYMIST) += milkymist-memcard.o
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										146
									
								
								hw/sd/core.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								hw/sd/core.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,146 @@
 | 
			
		||||
/*
 | 
			
		||||
 * SD card bus interface code.
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2015 Linaro Limited
 | 
			
		||||
 *
 | 
			
		||||
 * Author:
 | 
			
		||||
 *  Peter Maydell <peter.maydell@linaro.org>
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify it
 | 
			
		||||
 * under the terms and conditions of the GNU General Public License,
 | 
			
		||||
 * version 2 or later, as published by the Free Software Foundation.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope 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/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "qemu/osdep.h"
 | 
			
		||||
#include "hw/qdev-core.h"
 | 
			
		||||
#include "sysemu/block-backend.h"
 | 
			
		||||
#include "hw/sd/sd.h"
 | 
			
		||||
 | 
			
		||||
static SDState *get_card(SDBus *sdbus)
 | 
			
		||||
{
 | 
			
		||||
    /* We only ever have one child on the bus so just return it */
 | 
			
		||||
    BusChild *kid = QTAILQ_FIRST(&sdbus->qbus.children);
 | 
			
		||||
 | 
			
		||||
    if (!kid) {
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    return SD_CARD(kid->child);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int sdbus_do_command(SDBus *sdbus, SDRequest *req, uint8_t *response)
 | 
			
		||||
{
 | 
			
		||||
    SDState *card = get_card(sdbus);
 | 
			
		||||
 | 
			
		||||
    if (card) {
 | 
			
		||||
        SDCardClass *sc = SD_CARD_GET_CLASS(card);
 | 
			
		||||
 | 
			
		||||
        return sc->do_command(card, req, response);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void sdbus_write_data(SDBus *sdbus, uint8_t value)
 | 
			
		||||
{
 | 
			
		||||
    SDState *card = get_card(sdbus);
 | 
			
		||||
 | 
			
		||||
    if (card) {
 | 
			
		||||
        SDCardClass *sc = SD_CARD_GET_CLASS(card);
 | 
			
		||||
 | 
			
		||||
        sc->write_data(card, value);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t sdbus_read_data(SDBus *sdbus)
 | 
			
		||||
{
 | 
			
		||||
    SDState *card = get_card(sdbus);
 | 
			
		||||
 | 
			
		||||
    if (card) {
 | 
			
		||||
        SDCardClass *sc = SD_CARD_GET_CLASS(card);
 | 
			
		||||
 | 
			
		||||
        return sc->read_data(card);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool sdbus_data_ready(SDBus *sdbus)
 | 
			
		||||
{
 | 
			
		||||
    SDState *card = get_card(sdbus);
 | 
			
		||||
 | 
			
		||||
    if (card) {
 | 
			
		||||
        SDCardClass *sc = SD_CARD_GET_CLASS(card);
 | 
			
		||||
 | 
			
		||||
        return sc->data_ready(card);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool sdbus_get_inserted(SDBus *sdbus)
 | 
			
		||||
{
 | 
			
		||||
    SDState *card = get_card(sdbus);
 | 
			
		||||
 | 
			
		||||
    if (card) {
 | 
			
		||||
        SDCardClass *sc = SD_CARD_GET_CLASS(card);
 | 
			
		||||
 | 
			
		||||
        return sc->get_inserted(card);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool sdbus_get_readonly(SDBus *sdbus)
 | 
			
		||||
{
 | 
			
		||||
    SDState *card = get_card(sdbus);
 | 
			
		||||
 | 
			
		||||
    if (card) {
 | 
			
		||||
        SDCardClass *sc = SD_CARD_GET_CLASS(card);
 | 
			
		||||
 | 
			
		||||
        return sc->get_readonly(card);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void sdbus_set_inserted(SDBus *sdbus, bool inserted)
 | 
			
		||||
{
 | 
			
		||||
    SDBusClass *sbc = SD_BUS_GET_CLASS(sdbus);
 | 
			
		||||
    BusState *qbus = BUS(sdbus);
 | 
			
		||||
 | 
			
		||||
    if (sbc->set_inserted) {
 | 
			
		||||
        sbc->set_inserted(qbus->parent, inserted);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void sdbus_set_readonly(SDBus *sdbus, bool readonly)
 | 
			
		||||
{
 | 
			
		||||
    SDBusClass *sbc = SD_BUS_GET_CLASS(sdbus);
 | 
			
		||||
    BusState *qbus = BUS(sdbus);
 | 
			
		||||
 | 
			
		||||
    if (sbc->set_readonly) {
 | 
			
		||||
        sbc->set_readonly(qbus->parent, readonly);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const TypeInfo sd_bus_info = {
 | 
			
		||||
    .name = TYPE_SD_BUS,
 | 
			
		||||
    .parent = TYPE_BUS,
 | 
			
		||||
    .instance_size = sizeof(SDBus),
 | 
			
		||||
    .class_size = sizeof(SDBusClass),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void sd_bus_register_types(void)
 | 
			
		||||
{
 | 
			
		||||
    type_register_static(&sd_bus_info);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type_init(sd_bus_register_types)
 | 
			
		||||
@ -12,17 +12,31 @@
 | 
			
		||||
 | 
			
		||||
#include "qemu/osdep.h"
 | 
			
		||||
#include "hw/hw.h"
 | 
			
		||||
#include "hw/sysbus.h"
 | 
			
		||||
#include "hw/arm/pxa.h"
 | 
			
		||||
#include "hw/sd/sd.h"
 | 
			
		||||
#include "hw/qdev.h"
 | 
			
		||||
#include "hw/qdev-properties.h"
 | 
			
		||||
#include "qemu/error-report.h"
 | 
			
		||||
 | 
			
		||||
#define TYPE_PXA2XX_MMCI "pxa2xx-mmci"
 | 
			
		||||
#define PXA2XX_MMCI(obj) OBJECT_CHECK(PXA2xxMMCIState, (obj), TYPE_PXA2XX_MMCI)
 | 
			
		||||
 | 
			
		||||
#define TYPE_PXA2XX_MMCI_BUS "pxa2xx-mmci-bus"
 | 
			
		||||
#define PXA2XX_MMCI_BUS(obj) OBJECT_CHECK(SDBus, (obj), TYPE_PXA2XX_MMCI_BUS)
 | 
			
		||||
 | 
			
		||||
struct PXA2xxMMCIState {
 | 
			
		||||
    SysBusDevice parent_obj;
 | 
			
		||||
 | 
			
		||||
    MemoryRegion iomem;
 | 
			
		||||
    qemu_irq irq;
 | 
			
		||||
    qemu_irq rx_dma;
 | 
			
		||||
    qemu_irq tx_dma;
 | 
			
		||||
    qemu_irq inserted;
 | 
			
		||||
    qemu_irq readonly;
 | 
			
		||||
 | 
			
		||||
    SDState *card;
 | 
			
		||||
    BlockBackend *blk;
 | 
			
		||||
    SDBus sdbus;
 | 
			
		||||
 | 
			
		||||
    uint32_t status;
 | 
			
		||||
    uint32_t clkrt;
 | 
			
		||||
@ -30,25 +44,70 @@ struct PXA2xxMMCIState {
 | 
			
		||||
    uint32_t cmdat;
 | 
			
		||||
    uint32_t resp_tout;
 | 
			
		||||
    uint32_t read_tout;
 | 
			
		||||
    int blklen;
 | 
			
		||||
    int numblk;
 | 
			
		||||
    int32_t blklen;
 | 
			
		||||
    int32_t numblk;
 | 
			
		||||
    uint32_t intmask;
 | 
			
		||||
    uint32_t intreq;
 | 
			
		||||
    int cmd;
 | 
			
		||||
    int32_t cmd;
 | 
			
		||||
    uint32_t arg;
 | 
			
		||||
 | 
			
		||||
    int active;
 | 
			
		||||
    int bytesleft;
 | 
			
		||||
    int32_t active;
 | 
			
		||||
    int32_t bytesleft;
 | 
			
		||||
    uint8_t tx_fifo[64];
 | 
			
		||||
    int tx_start;
 | 
			
		||||
    int tx_len;
 | 
			
		||||
    uint32_t tx_start;
 | 
			
		||||
    uint32_t tx_len;
 | 
			
		||||
    uint8_t rx_fifo[32];
 | 
			
		||||
    int rx_start;
 | 
			
		||||
    int rx_len;
 | 
			
		||||
    uint32_t rx_start;
 | 
			
		||||
    uint32_t rx_len;
 | 
			
		||||
    uint16_t resp_fifo[9];
 | 
			
		||||
    int resp_len;
 | 
			
		||||
    uint32_t resp_len;
 | 
			
		||||
 | 
			
		||||
    int cmdreq;
 | 
			
		||||
    int32_t cmdreq;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static bool pxa2xx_mmci_vmstate_validate(void *opaque, int version_id)
 | 
			
		||||
{
 | 
			
		||||
    PXA2xxMMCIState *s = opaque;
 | 
			
		||||
 | 
			
		||||
    return s->tx_start < ARRAY_SIZE(s->tx_fifo)
 | 
			
		||||
        && s->rx_start < ARRAY_SIZE(s->rx_fifo)
 | 
			
		||||
        && s->tx_len <= ARRAY_SIZE(s->tx_fifo)
 | 
			
		||||
        && s->rx_len <= ARRAY_SIZE(s->rx_fifo)
 | 
			
		||||
        && s->resp_len <= ARRAY_SIZE(s->resp_fifo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static const VMStateDescription vmstate_pxa2xx_mmci = {
 | 
			
		||||
    .name = "pxa2xx-mmci",
 | 
			
		||||
    .version_id = 2,
 | 
			
		||||
    .minimum_version_id = 2,
 | 
			
		||||
    .fields = (VMStateField[]) {
 | 
			
		||||
        VMSTATE_UINT32(status, PXA2xxMMCIState),
 | 
			
		||||
        VMSTATE_UINT32(clkrt, PXA2xxMMCIState),
 | 
			
		||||
        VMSTATE_UINT32(spi, PXA2xxMMCIState),
 | 
			
		||||
        VMSTATE_UINT32(cmdat, PXA2xxMMCIState),
 | 
			
		||||
        VMSTATE_UINT32(resp_tout, PXA2xxMMCIState),
 | 
			
		||||
        VMSTATE_UINT32(read_tout, PXA2xxMMCIState),
 | 
			
		||||
        VMSTATE_INT32(blklen, PXA2xxMMCIState),
 | 
			
		||||
        VMSTATE_INT32(numblk, PXA2xxMMCIState),
 | 
			
		||||
        VMSTATE_UINT32(intmask, PXA2xxMMCIState),
 | 
			
		||||
        VMSTATE_UINT32(intreq, PXA2xxMMCIState),
 | 
			
		||||
        VMSTATE_INT32(cmd, PXA2xxMMCIState),
 | 
			
		||||
        VMSTATE_UINT32(arg, PXA2xxMMCIState),
 | 
			
		||||
        VMSTATE_INT32(cmdreq, PXA2xxMMCIState),
 | 
			
		||||
        VMSTATE_INT32(active, PXA2xxMMCIState),
 | 
			
		||||
        VMSTATE_INT32(bytesleft, PXA2xxMMCIState),
 | 
			
		||||
        VMSTATE_UINT32(tx_start, PXA2xxMMCIState),
 | 
			
		||||
        VMSTATE_UINT32(tx_len, PXA2xxMMCIState),
 | 
			
		||||
        VMSTATE_UINT32(rx_start, PXA2xxMMCIState),
 | 
			
		||||
        VMSTATE_UINT32(rx_len, PXA2xxMMCIState),
 | 
			
		||||
        VMSTATE_UINT32(resp_len, PXA2xxMMCIState),
 | 
			
		||||
        VMSTATE_VALIDATE("fifo size incorrect", pxa2xx_mmci_vmstate_validate),
 | 
			
		||||
        VMSTATE_UINT8_ARRAY(tx_fifo, PXA2xxMMCIState, 64),
 | 
			
		||||
        VMSTATE_UINT8_ARRAY(rx_fifo, PXA2xxMMCIState, 32),
 | 
			
		||||
        VMSTATE_UINT16_ARRAY(resp_fifo, PXA2xxMMCIState, 9),
 | 
			
		||||
        VMSTATE_END_OF_LIST()
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define MMC_STRPCL	0x00	/* MMC Clock Start/Stop register */
 | 
			
		||||
@ -122,7 +181,7 @@ static void pxa2xx_mmci_fifo_update(PXA2xxMMCIState *s)
 | 
			
		||||
 | 
			
		||||
    if (s->cmdat & CMDAT_WR_RD) {
 | 
			
		||||
        while (s->bytesleft && s->tx_len) {
 | 
			
		||||
            sd_write_data(s->card, s->tx_fifo[s->tx_start ++]);
 | 
			
		||||
            sdbus_write_data(&s->sdbus, s->tx_fifo[s->tx_start++]);
 | 
			
		||||
            s->tx_start &= 0x1f;
 | 
			
		||||
            s->tx_len --;
 | 
			
		||||
            s->bytesleft --;
 | 
			
		||||
@ -132,7 +191,7 @@ static void pxa2xx_mmci_fifo_update(PXA2xxMMCIState *s)
 | 
			
		||||
    } else
 | 
			
		||||
        while (s->bytesleft && s->rx_len < 32) {
 | 
			
		||||
            s->rx_fifo[(s->rx_start + (s->rx_len ++)) & 0x1f] =
 | 
			
		||||
                sd_read_data(s->card);
 | 
			
		||||
                sdbus_read_data(&s->sdbus);
 | 
			
		||||
            s->bytesleft --;
 | 
			
		||||
            s->intreq |= INT_RXFIFO_REQ;
 | 
			
		||||
        }
 | 
			
		||||
@ -166,7 +225,7 @@ static void pxa2xx_mmci_wakequeues(PXA2xxMMCIState *s)
 | 
			
		||||
    request.arg = s->arg;
 | 
			
		||||
    request.crc = 0;	/* FIXME */
 | 
			
		||||
 | 
			
		||||
    rsplen = sd_do_command(s->card, &request, response);
 | 
			
		||||
    rsplen = sdbus_do_command(&s->sdbus, &request, response);
 | 
			
		||||
    s->intreq |= INT_END_CMD;
 | 
			
		||||
 | 
			
		||||
    memset(s->resp_fifo, 0, sizeof(s->resp_fifo));
 | 
			
		||||
@ -392,114 +451,147 @@ static const MemoryRegionOps pxa2xx_mmci_ops = {
 | 
			
		||||
    .endianness = DEVICE_NATIVE_ENDIAN,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void pxa2xx_mmci_save(QEMUFile *f, void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    qemu_put_be32s(f, &s->status);
 | 
			
		||||
    qemu_put_be32s(f, &s->clkrt);
 | 
			
		||||
    qemu_put_be32s(f, &s->spi);
 | 
			
		||||
    qemu_put_be32s(f, &s->cmdat);
 | 
			
		||||
    qemu_put_be32s(f, &s->resp_tout);
 | 
			
		||||
    qemu_put_be32s(f, &s->read_tout);
 | 
			
		||||
    qemu_put_be32(f, s->blklen);
 | 
			
		||||
    qemu_put_be32(f, s->numblk);
 | 
			
		||||
    qemu_put_be32s(f, &s->intmask);
 | 
			
		||||
    qemu_put_be32s(f, &s->intreq);
 | 
			
		||||
    qemu_put_be32(f, s->cmd);
 | 
			
		||||
    qemu_put_be32s(f, &s->arg);
 | 
			
		||||
    qemu_put_be32(f, s->cmdreq);
 | 
			
		||||
    qemu_put_be32(f, s->active);
 | 
			
		||||
    qemu_put_be32(f, s->bytesleft);
 | 
			
		||||
 | 
			
		||||
    qemu_put_byte(f, s->tx_len);
 | 
			
		||||
    for (i = 0; i < s->tx_len; i ++)
 | 
			
		||||
        qemu_put_byte(f, s->tx_fifo[(s->tx_start + i) & 63]);
 | 
			
		||||
 | 
			
		||||
    qemu_put_byte(f, s->rx_len);
 | 
			
		||||
    for (i = 0; i < s->rx_len; i ++)
 | 
			
		||||
        qemu_put_byte(f, s->rx_fifo[(s->rx_start + i) & 31]);
 | 
			
		||||
 | 
			
		||||
    qemu_put_byte(f, s->resp_len);
 | 
			
		||||
    for (i = s->resp_len; i < 9; i ++)
 | 
			
		||||
        qemu_put_be16s(f, &s->resp_fifo[i]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int pxa2xx_mmci_load(QEMUFile *f, void *opaque, int version_id)
 | 
			
		||||
{
 | 
			
		||||
    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    qemu_get_be32s(f, &s->status);
 | 
			
		||||
    qemu_get_be32s(f, &s->clkrt);
 | 
			
		||||
    qemu_get_be32s(f, &s->spi);
 | 
			
		||||
    qemu_get_be32s(f, &s->cmdat);
 | 
			
		||||
    qemu_get_be32s(f, &s->resp_tout);
 | 
			
		||||
    qemu_get_be32s(f, &s->read_tout);
 | 
			
		||||
    s->blklen = qemu_get_be32(f);
 | 
			
		||||
    s->numblk = qemu_get_be32(f);
 | 
			
		||||
    qemu_get_be32s(f, &s->intmask);
 | 
			
		||||
    qemu_get_be32s(f, &s->intreq);
 | 
			
		||||
    s->cmd = qemu_get_be32(f);
 | 
			
		||||
    qemu_get_be32s(f, &s->arg);
 | 
			
		||||
    s->cmdreq = qemu_get_be32(f);
 | 
			
		||||
    s->active = qemu_get_be32(f);
 | 
			
		||||
    s->bytesleft = qemu_get_be32(f);
 | 
			
		||||
 | 
			
		||||
    s->tx_len = qemu_get_byte(f);
 | 
			
		||||
    s->tx_start = 0;
 | 
			
		||||
    if (s->tx_len >= sizeof(s->tx_fifo) || s->tx_len < 0)
 | 
			
		||||
        return -EINVAL;
 | 
			
		||||
    for (i = 0; i < s->tx_len; i ++)
 | 
			
		||||
        s->tx_fifo[i] = qemu_get_byte(f);
 | 
			
		||||
 | 
			
		||||
    s->rx_len = qemu_get_byte(f);
 | 
			
		||||
    s->rx_start = 0;
 | 
			
		||||
    if (s->rx_len >= sizeof(s->rx_fifo) || s->rx_len < 0)
 | 
			
		||||
        return -EINVAL;
 | 
			
		||||
    for (i = 0; i < s->rx_len; i ++)
 | 
			
		||||
        s->rx_fifo[i] = qemu_get_byte(f);
 | 
			
		||||
 | 
			
		||||
    s->resp_len = qemu_get_byte(f);
 | 
			
		||||
    if (s->resp_len > 9 || s->resp_len < 0)
 | 
			
		||||
        return -EINVAL;
 | 
			
		||||
    for (i = s->resp_len; i < 9; i ++)
 | 
			
		||||
         qemu_get_be16s(f, &s->resp_fifo[i]);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PXA2xxMMCIState *pxa2xx_mmci_init(MemoryRegion *sysmem,
 | 
			
		||||
                hwaddr base,
 | 
			
		||||
                BlockBackend *blk, qemu_irq irq,
 | 
			
		||||
                qemu_irq rx_dma, qemu_irq tx_dma)
 | 
			
		||||
{
 | 
			
		||||
    DeviceState *dev, *carddev;
 | 
			
		||||
    SysBusDevice *sbd;
 | 
			
		||||
    PXA2xxMMCIState *s;
 | 
			
		||||
    Error *err = NULL;
 | 
			
		||||
 | 
			
		||||
    s = (PXA2xxMMCIState *) g_malloc0(sizeof(PXA2xxMMCIState));
 | 
			
		||||
    s->irq = irq;
 | 
			
		||||
    s->rx_dma = rx_dma;
 | 
			
		||||
    s->tx_dma = tx_dma;
 | 
			
		||||
    dev = qdev_create(NULL, TYPE_PXA2XX_MMCI);
 | 
			
		||||
    s = PXA2XX_MMCI(dev);
 | 
			
		||||
    sbd = SYS_BUS_DEVICE(dev);
 | 
			
		||||
    sysbus_mmio_map(sbd, 0, base);
 | 
			
		||||
    sysbus_connect_irq(sbd, 0, irq);
 | 
			
		||||
    qdev_connect_gpio_out_named(dev, "rx-dma", 0, rx_dma);
 | 
			
		||||
    qdev_connect_gpio_out_named(dev, "tx-dma", 0, tx_dma);
 | 
			
		||||
 | 
			
		||||
    memory_region_init_io(&s->iomem, NULL, &pxa2xx_mmci_ops, s,
 | 
			
		||||
                          "pxa2xx-mmci", 0x00100000);
 | 
			
		||||
    memory_region_add_subregion(sysmem, base, &s->iomem);
 | 
			
		||||
 | 
			
		||||
    /* Instantiate the actual storage */
 | 
			
		||||
    s->card = sd_init(blk, false);
 | 
			
		||||
    if (s->card == NULL) {
 | 
			
		||||
        exit(1);
 | 
			
		||||
    /* Create and plug in the sd card */
 | 
			
		||||
    carddev = qdev_create(qdev_get_child_bus(dev, "sd-bus"), TYPE_SD_CARD);
 | 
			
		||||
    qdev_prop_set_drive(carddev, "drive", blk, &err);
 | 
			
		||||
    if (err) {
 | 
			
		||||
        error_report("failed to init SD card: %s", error_get_pretty(err));
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    object_property_set_bool(OBJECT(carddev), true, "realized", &err);
 | 
			
		||||
    if (err) {
 | 
			
		||||
        error_report("failed to init SD card: %s", error_get_pretty(err));
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    register_savevm(NULL, "pxa2xx_mmci", 0, 0,
 | 
			
		||||
                    pxa2xx_mmci_save, pxa2xx_mmci_load, s);
 | 
			
		||||
 | 
			
		||||
    return s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void pxa2xx_mmci_set_inserted(DeviceState *dev, bool inserted)
 | 
			
		||||
{
 | 
			
		||||
    PXA2xxMMCIState *s = PXA2XX_MMCI(dev);
 | 
			
		||||
 | 
			
		||||
    qemu_set_irq(s->inserted, inserted);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void pxa2xx_mmci_set_readonly(DeviceState *dev, bool readonly)
 | 
			
		||||
{
 | 
			
		||||
    PXA2xxMMCIState *s = PXA2XX_MMCI(dev);
 | 
			
		||||
 | 
			
		||||
    qemu_set_irq(s->readonly, readonly);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pxa2xx_mmci_handlers(PXA2xxMMCIState *s, qemu_irq readonly,
 | 
			
		||||
                          qemu_irq coverswitch)
 | 
			
		||||
{
 | 
			
		||||
    sd_set_cb(s->card, readonly, coverswitch);
 | 
			
		||||
    DeviceState *dev = DEVICE(s);
 | 
			
		||||
 | 
			
		||||
    s->readonly = readonly;
 | 
			
		||||
    s->inserted = coverswitch;
 | 
			
		||||
 | 
			
		||||
    pxa2xx_mmci_set_inserted(dev, sdbus_get_inserted(&s->sdbus));
 | 
			
		||||
    pxa2xx_mmci_set_readonly(dev, sdbus_get_readonly(&s->sdbus));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void pxa2xx_mmci_reset(DeviceState *d)
 | 
			
		||||
{
 | 
			
		||||
    PXA2xxMMCIState *s = PXA2XX_MMCI(d);
 | 
			
		||||
 | 
			
		||||
    s->status = 0;
 | 
			
		||||
    s->clkrt = 0;
 | 
			
		||||
    s->spi = 0;
 | 
			
		||||
    s->cmdat = 0;
 | 
			
		||||
    s->resp_tout = 0;
 | 
			
		||||
    s->read_tout = 0;
 | 
			
		||||
    s->blklen = 0;
 | 
			
		||||
    s->numblk = 0;
 | 
			
		||||
    s->intmask = 0;
 | 
			
		||||
    s->intreq = 0;
 | 
			
		||||
    s->cmd = 0;
 | 
			
		||||
    s->arg = 0;
 | 
			
		||||
    s->active = 0;
 | 
			
		||||
    s->bytesleft = 0;
 | 
			
		||||
    s->tx_start = 0;
 | 
			
		||||
    s->tx_len = 0;
 | 
			
		||||
    s->rx_start = 0;
 | 
			
		||||
    s->rx_len = 0;
 | 
			
		||||
    s->resp_len = 0;
 | 
			
		||||
    s->cmdreq = 0;
 | 
			
		||||
    memset(s->tx_fifo, 0, sizeof(s->tx_fifo));
 | 
			
		||||
    memset(s->rx_fifo, 0, sizeof(s->rx_fifo));
 | 
			
		||||
    memset(s->resp_fifo, 0, sizeof(s->resp_fifo));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void pxa2xx_mmci_instance_init(Object *obj)
 | 
			
		||||
{
 | 
			
		||||
    PXA2xxMMCIState *s = PXA2XX_MMCI(obj);
 | 
			
		||||
    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 | 
			
		||||
    DeviceState *dev = DEVICE(obj);
 | 
			
		||||
 | 
			
		||||
    memory_region_init_io(&s->iomem, obj, &pxa2xx_mmci_ops, s,
 | 
			
		||||
                          "pxa2xx-mmci", 0x00100000);
 | 
			
		||||
    sysbus_init_mmio(sbd, &s->iomem);
 | 
			
		||||
    sysbus_init_irq(sbd, &s->irq);
 | 
			
		||||
    qdev_init_gpio_out_named(dev, &s->rx_dma, "rx-dma", 1);
 | 
			
		||||
    qdev_init_gpio_out_named(dev, &s->tx_dma, "tx-dma", 1);
 | 
			
		||||
 | 
			
		||||
    qbus_create_inplace(&s->sdbus, sizeof(s->sdbus),
 | 
			
		||||
                        TYPE_PXA2XX_MMCI_BUS, DEVICE(obj), "sd-bus");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void pxa2xx_mmci_class_init(ObjectClass *klass, void *data)
 | 
			
		||||
{
 | 
			
		||||
    DeviceClass *dc = DEVICE_CLASS(klass);
 | 
			
		||||
 | 
			
		||||
    dc->vmsd = &vmstate_pxa2xx_mmci;
 | 
			
		||||
    dc->reset = pxa2xx_mmci_reset;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void pxa2xx_mmci_bus_class_init(ObjectClass *klass, void *data)
 | 
			
		||||
{
 | 
			
		||||
    SDBusClass *sbc = SD_BUS_CLASS(klass);
 | 
			
		||||
 | 
			
		||||
    sbc->set_inserted = pxa2xx_mmci_set_inserted;
 | 
			
		||||
    sbc->set_readonly = pxa2xx_mmci_set_readonly;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const TypeInfo pxa2xx_mmci_info = {
 | 
			
		||||
    .name = TYPE_PXA2XX_MMCI,
 | 
			
		||||
    .parent = TYPE_SYS_BUS_DEVICE,
 | 
			
		||||
    .instance_size = sizeof(PXA2xxMMCIState),
 | 
			
		||||
    .instance_init = pxa2xx_mmci_instance_init,
 | 
			
		||||
    .class_init = pxa2xx_mmci_class_init,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const TypeInfo pxa2xx_mmci_bus_info = {
 | 
			
		||||
    .name = TYPE_PXA2XX_MMCI_BUS,
 | 
			
		||||
    .parent = TYPE_SD_BUS,
 | 
			
		||||
    .instance_size = sizeof(SDBus),
 | 
			
		||||
    .class_init = pxa2xx_mmci_bus_class_init,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void pxa2xx_mmci_register_types(void)
 | 
			
		||||
{
 | 
			
		||||
    type_register_static(&pxa2xx_mmci_info);
 | 
			
		||||
    type_register_static(&pxa2xx_mmci_bus_info);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type_init(pxa2xx_mmci_register_types)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										287
									
								
								hw/sd/sd.c
									
									
									
									
									
								
							
							
						
						
									
										287
									
								
								hw/sd/sd.c
									
									
									
									
									
								
							@ -30,10 +30,14 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "qemu/osdep.h"
 | 
			
		||||
#include "hw/qdev.h"
 | 
			
		||||
#include "hw/hw.h"
 | 
			
		||||
#include "sysemu/block-backend.h"
 | 
			
		||||
#include "hw/sd/sd.h"
 | 
			
		||||
#include "qemu/bitmap.h"
 | 
			
		||||
#include "hw/qdev-properties.h"
 | 
			
		||||
#include "qemu/error-report.h"
 | 
			
		||||
#include "qemu/timer.h"
 | 
			
		||||
 | 
			
		||||
//#define DEBUG_SD 1
 | 
			
		||||
 | 
			
		||||
@ -45,6 +49,8 @@ do { fprintf(stderr, "SD: " fmt , ## __VA_ARGS__); } while (0)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define ACMD41_ENQUIRY_MASK     0x00ffffff
 | 
			
		||||
#define OCR_POWER_UP            0x80000000
 | 
			
		||||
#define OCR_POWER_DELAY_NS      500000 /* 0.5ms */
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    sd_r0 = 0,    /* no response */
 | 
			
		||||
@ -78,9 +84,12 @@ enum SDCardStates {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct SDState {
 | 
			
		||||
    DeviceState parent_obj;
 | 
			
		||||
 | 
			
		||||
    uint32_t mode;    /* current card mode, one of SDCardModes */
 | 
			
		||||
    int32_t state;    /* current card state, one of SDCardStates */
 | 
			
		||||
    uint32_t ocr;
 | 
			
		||||
    QEMUTimer *ocr_power_timer;
 | 
			
		||||
    uint8_t scr[8];
 | 
			
		||||
    uint8_t cid[16];
 | 
			
		||||
    uint8_t csd[16];
 | 
			
		||||
@ -93,6 +102,7 @@ struct SDState {
 | 
			
		||||
    int32_t wpgrps_size;
 | 
			
		||||
    uint64_t size;
 | 
			
		||||
    uint32_t blk_len;
 | 
			
		||||
    uint32_t multi_blk_cnt;
 | 
			
		||||
    uint32_t erase_start;
 | 
			
		||||
    uint32_t erase_end;
 | 
			
		||||
    uint8_t pwd[16];
 | 
			
		||||
@ -194,8 +204,17 @@ static uint16_t sd_crc16(void *message, size_t width)
 | 
			
		||||
 | 
			
		||||
static void sd_set_ocr(SDState *sd)
 | 
			
		||||
{
 | 
			
		||||
    /* All voltages OK, card power-up OK, Standard Capacity SD Memory Card */
 | 
			
		||||
    sd->ocr = 0x80ffff00;
 | 
			
		||||
    /* All voltages OK, Standard Capacity SD Memory Card, not yet powered up */
 | 
			
		||||
    sd->ocr = 0x00ffff00;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void sd_ocr_powerup(void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    SDState *sd = opaque;
 | 
			
		||||
 | 
			
		||||
    /* Set powered up bit in OCR */
 | 
			
		||||
    assert(!(sd->ocr & OCR_POWER_UP));
 | 
			
		||||
    sd->ocr |= OCR_POWER_UP;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void sd_set_scr(SDState *sd)
 | 
			
		||||
@ -390,8 +409,9 @@ static inline uint64_t sd_addr_to_wpnum(uint64_t addr)
 | 
			
		||||
    return addr >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void sd_reset(SDState *sd)
 | 
			
		||||
static void sd_reset(DeviceState *dev)
 | 
			
		||||
{
 | 
			
		||||
    SDState *sd = SD_CARD(dev);
 | 
			
		||||
    uint64_t size;
 | 
			
		||||
    uint64_t sect;
 | 
			
		||||
 | 
			
		||||
@ -424,16 +444,44 @@ static void sd_reset(SDState *sd)
 | 
			
		||||
    sd->blk_len = 0x200;
 | 
			
		||||
    sd->pwd_len = 0;
 | 
			
		||||
    sd->expecting_acmd = false;
 | 
			
		||||
    sd->multi_blk_cnt = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool sd_get_inserted(SDState *sd)
 | 
			
		||||
{
 | 
			
		||||
    return blk_is_inserted(sd->blk);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool sd_get_readonly(SDState *sd)
 | 
			
		||||
{
 | 
			
		||||
    return sd->wp_switch;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void sd_cardchange(void *opaque, bool load)
 | 
			
		||||
{
 | 
			
		||||
    SDState *sd = opaque;
 | 
			
		||||
    DeviceState *dev = DEVICE(sd);
 | 
			
		||||
    SDBus *sdbus = SD_BUS(qdev_get_parent_bus(dev));
 | 
			
		||||
    bool inserted = sd_get_inserted(sd);
 | 
			
		||||
    bool readonly = sd_get_readonly(sd);
 | 
			
		||||
 | 
			
		||||
    qemu_set_irq(sd->inserted_cb, blk_is_inserted(sd->blk));
 | 
			
		||||
    if (blk_is_inserted(sd->blk)) {
 | 
			
		||||
        sd_reset(sd);
 | 
			
		||||
        qemu_set_irq(sd->readonly_cb, sd->wp_switch);
 | 
			
		||||
    if (inserted) {
 | 
			
		||||
        sd_reset(dev);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* The IRQ notification is for legacy non-QOM SD controller devices;
 | 
			
		||||
     * QOMified controllers use the SDBus APIs.
 | 
			
		||||
     */
 | 
			
		||||
    if (sdbus) {
 | 
			
		||||
        sdbus_set_inserted(sdbus, inserted);
 | 
			
		||||
        if (inserted) {
 | 
			
		||||
            sdbus_set_readonly(sdbus, readonly);
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        qemu_set_irq(sd->inserted_cb, inserted);
 | 
			
		||||
        if (inserted) {
 | 
			
		||||
            qemu_set_irq(sd->readonly_cb, readonly);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -441,10 +489,44 @@ static const BlockDevOps sd_block_ops = {
 | 
			
		||||
    .change_media_cb = sd_cardchange,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static bool sd_ocr_vmstate_needed(void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    SDState *sd = opaque;
 | 
			
		||||
 | 
			
		||||
    /* Include the OCR state (and timer) if it is not yet powered up */
 | 
			
		||||
    return !(sd->ocr & OCR_POWER_UP);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const VMStateDescription sd_ocr_vmstate = {
 | 
			
		||||
    .name = "sd-card/ocr-state",
 | 
			
		||||
    .version_id = 1,
 | 
			
		||||
    .minimum_version_id = 1,
 | 
			
		||||
    .needed = sd_ocr_vmstate_needed,
 | 
			
		||||
    .fields = (VMStateField[]) {
 | 
			
		||||
        VMSTATE_UINT32(ocr, SDState),
 | 
			
		||||
        VMSTATE_TIMER_PTR(ocr_power_timer, SDState),
 | 
			
		||||
        VMSTATE_END_OF_LIST()
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int sd_vmstate_pre_load(void *opaque)
 | 
			
		||||
{
 | 
			
		||||
    SDState *sd = opaque;
 | 
			
		||||
 | 
			
		||||
    /* If the OCR state is not included (prior versions, or not
 | 
			
		||||
     * needed), then the OCR must be set as powered up. If the OCR state
 | 
			
		||||
     * is included, this will be replaced by the state restore.
 | 
			
		||||
     */
 | 
			
		||||
    sd_ocr_powerup(sd);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const VMStateDescription sd_vmstate = {
 | 
			
		||||
    .name = "sd-card",
 | 
			
		||||
    .version_id = 1,
 | 
			
		||||
    .minimum_version_id = 1,
 | 
			
		||||
    .pre_load = sd_vmstate_pre_load,
 | 
			
		||||
    .fields = (VMStateField[]) {
 | 
			
		||||
        VMSTATE_UINT32(mode, SDState),
 | 
			
		||||
        VMSTATE_INT32(state, SDState),
 | 
			
		||||
@ -456,6 +538,7 @@ static const VMStateDescription sd_vmstate = {
 | 
			
		||||
        VMSTATE_UINT32(vhs, SDState),
 | 
			
		||||
        VMSTATE_BITMAP(wp_groups, SDState, 0, wpgrps_size),
 | 
			
		||||
        VMSTATE_UINT32(blk_len, SDState),
 | 
			
		||||
        VMSTATE_UINT32(multi_blk_cnt, SDState),
 | 
			
		||||
        VMSTATE_UINT32(erase_start, SDState),
 | 
			
		||||
        VMSTATE_UINT32(erase_end, SDState),
 | 
			
		||||
        VMSTATE_UINT8_ARRAY(pwd, SDState, 16),
 | 
			
		||||
@ -470,37 +553,33 @@ static const VMStateDescription sd_vmstate = {
 | 
			
		||||
        VMSTATE_BUFFER_POINTER_UNSAFE(buf, SDState, 1, 512),
 | 
			
		||||
        VMSTATE_BOOL(enable, SDState),
 | 
			
		||||
        VMSTATE_END_OF_LIST()
 | 
			
		||||
    }
 | 
			
		||||
    },
 | 
			
		||||
    .subsections = (const VMStateDescription*[]) {
 | 
			
		||||
        &sd_ocr_vmstate,
 | 
			
		||||
        NULL
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* We do not model the chip select pin, so allow the board to select
 | 
			
		||||
   whether card should be in SSI or MMC/SD mode.  It is also up to the
 | 
			
		||||
   board to ensure that ssi transfers only occur when the chip select
 | 
			
		||||
   is asserted.  */
 | 
			
		||||
/* Legacy initialization function for use by non-qdevified callers */
 | 
			
		||||
SDState *sd_init(BlockBackend *blk, bool is_spi)
 | 
			
		||||
{
 | 
			
		||||
    SDState *sd;
 | 
			
		||||
    DeviceState *dev;
 | 
			
		||||
    Error *err = NULL;
 | 
			
		||||
 | 
			
		||||
    if (blk && blk_is_read_only(blk)) {
 | 
			
		||||
        fprintf(stderr, "sd_init: Cannot use read-only drive\n");
 | 
			
		||||
    dev = qdev_create(NULL, TYPE_SD_CARD);
 | 
			
		||||
    qdev_prop_set_drive(dev, "drive", blk, &err);
 | 
			
		||||
    if (err) {
 | 
			
		||||
        error_report("sd_init failed: %s", error_get_pretty(err));
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    qdev_prop_set_bit(dev, "spi", is_spi);
 | 
			
		||||
    object_property_set_bool(OBJECT(dev), true, "realized", &err);
 | 
			
		||||
    if (err) {
 | 
			
		||||
        error_report("sd_init failed: %s", error_get_pretty(err));
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sd = (SDState *) g_malloc0(sizeof(SDState));
 | 
			
		||||
    sd->buf = blk_blockalign(blk, 512);
 | 
			
		||||
    sd->spi = is_spi;
 | 
			
		||||
    sd->enable = true;
 | 
			
		||||
    sd->blk = blk;
 | 
			
		||||
    sd_reset(sd);
 | 
			
		||||
    if (sd->blk) {
 | 
			
		||||
        /* Attach dev if not already attached.  (This call ignores an
 | 
			
		||||
         * error return code if sd->blk is already attached.) */
 | 
			
		||||
        /* FIXME ignoring blk_attach_dev() failure is dangerously brittle */
 | 
			
		||||
        blk_attach_dev(sd->blk, sd);
 | 
			
		||||
        blk_set_dev_ops(sd->blk, &sd_block_ops, sd);
 | 
			
		||||
    }
 | 
			
		||||
    vmstate_register(NULL, -1, &sd_vmstate, sd);
 | 
			
		||||
    return sd;
 | 
			
		||||
    return SD_CARD(dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert)
 | 
			
		||||
@ -674,6 +753,12 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
 | 
			
		||||
        rca = req.arg >> 16;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* CMD23 (set block count) must be immediately followed by CMD18 or CMD25
 | 
			
		||||
     * if not, its effects are cancelled */
 | 
			
		||||
    if (sd->multi_blk_cnt != 0 && !(req.cmd == 18 || req.cmd == 25)) {
 | 
			
		||||
        sd->multi_blk_cnt = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    DPRINTF("CMD%d 0x%08x state %d\n", req.cmd, req.arg, sd->state);
 | 
			
		||||
    switch (req.cmd) {
 | 
			
		||||
    /* Basic commands (Class 0 and Class 1) */
 | 
			
		||||
@ -684,7 +769,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            sd->state = sd_idle_state;
 | 
			
		||||
            sd_reset(sd);
 | 
			
		||||
            sd_reset(DEVICE(sd));
 | 
			
		||||
            return sd->spi ? sd_r1 : sd_r0;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
@ -969,6 +1054,17 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    case 23:    /* CMD23: SET_BLOCK_COUNT */
 | 
			
		||||
        switch (sd->state) {
 | 
			
		||||
        case sd_transfer_state:
 | 
			
		||||
            sd->multi_blk_cnt = req.arg;
 | 
			
		||||
            return sd_r1;
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    /* Block write commands (Class 4) */
 | 
			
		||||
    case 24:	/* CMD24:  WRITE_SINGLE_BLOCK */
 | 
			
		||||
        if (sd->spi)
 | 
			
		||||
@ -1201,16 +1297,17 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
    bad_cmd:
 | 
			
		||||
        fprintf(stderr, "SD: Unknown CMD%i\n", req.cmd);
 | 
			
		||||
        qemu_log_mask(LOG_GUEST_ERROR, "SD: Unknown CMD%i\n", req.cmd);
 | 
			
		||||
        return sd_illegal;
 | 
			
		||||
 | 
			
		||||
    unimplemented_cmd:
 | 
			
		||||
        /* Commands that are recognised but not yet implemented in SPI mode.  */
 | 
			
		||||
        fprintf(stderr, "SD: CMD%i not implemented in SPI mode\n", req.cmd);
 | 
			
		||||
        qemu_log_mask(LOG_UNIMP, "SD: CMD%i not implemented in SPI mode\n",
 | 
			
		||||
                      req.cmd);
 | 
			
		||||
        return sd_illegal;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fprintf(stderr, "SD: CMD%i in a wrong state\n", req.cmd);
 | 
			
		||||
    qemu_log_mask(LOG_GUEST_ERROR, "SD: CMD%i in a wrong state\n", req.cmd);
 | 
			
		||||
    return sd_illegal;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1278,9 +1375,28 @@ static sd_rsp_type_t sd_app_command(SDState *sd,
 | 
			
		||||
        }
 | 
			
		||||
        switch (sd->state) {
 | 
			
		||||
        case sd_idle_state:
 | 
			
		||||
            /* If it's the first ACMD41 since reset, we need to decide
 | 
			
		||||
             * whether to power up. If this is not an enquiry ACMD41,
 | 
			
		||||
             * we immediately report power on and proceed below to the
 | 
			
		||||
             * ready state, but if it is, we set a timer to model a
 | 
			
		||||
             * delay for power up. This works around a bug in EDK2
 | 
			
		||||
             * UEFI, which sends an initial enquiry ACMD41, but
 | 
			
		||||
             * assumes that the card is in ready state as soon as it
 | 
			
		||||
             * sees the power up bit set. */
 | 
			
		||||
            if (!(sd->ocr & OCR_POWER_UP)) {
 | 
			
		||||
                if ((req.arg & ACMD41_ENQUIRY_MASK) != 0) {
 | 
			
		||||
                    timer_del(sd->ocr_power_timer);
 | 
			
		||||
                    sd_ocr_powerup(sd);
 | 
			
		||||
                } else if (!timer_pending(sd->ocr_power_timer)) {
 | 
			
		||||
                    timer_mod_ns(sd->ocr_power_timer,
 | 
			
		||||
                                 (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)
 | 
			
		||||
                                  + OCR_POWER_DELAY_NS));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /* We accept any voltage.  10000 V is nothing.
 | 
			
		||||
             *
 | 
			
		||||
             * We don't model init delay so just advance straight to ready state
 | 
			
		||||
             * Once we're powered up, we advance straight to ready state
 | 
			
		||||
             * unless it's an enquiry ACMD41 (bits 23:0 == 0).
 | 
			
		||||
             */
 | 
			
		||||
            if (req.arg & ACMD41_ENQUIRY_MASK) {
 | 
			
		||||
@ -1323,7 +1439,7 @@ static sd_rsp_type_t sd_app_command(SDState *sd,
 | 
			
		||||
        return sd_normal_command(sd, req);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fprintf(stderr, "SD: ACMD%i in a wrong state\n", req.cmd);
 | 
			
		||||
    qemu_log_mask(LOG_GUEST_ERROR, "SD: ACMD%i in a wrong state\n", req.cmd);
 | 
			
		||||
    return sd_illegal;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1367,7 +1483,7 @@ int sd_do_command(SDState *sd, SDRequest *req,
 | 
			
		||||
        if (!cmd_valid_while_locked(sd, req)) {
 | 
			
		||||
            sd->card_status |= ILLEGAL_COMMAND;
 | 
			
		||||
            sd->expecting_acmd = false;
 | 
			
		||||
            fprintf(stderr, "SD: Card is locked\n");
 | 
			
		||||
            qemu_log_mask(LOG_GUEST_ERROR, "SD: Card is locked\n");
 | 
			
		||||
            rtype = sd_illegal;
 | 
			
		||||
            goto send_response;
 | 
			
		||||
        }
 | 
			
		||||
@ -1525,7 +1641,8 @@ void sd_write_data(SDState *sd, uint8_t value)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if (sd->state != sd_receivingdata_state) {
 | 
			
		||||
        fprintf(stderr, "sd_write_data: not in Receiving-Data state\n");
 | 
			
		||||
        qemu_log_mask(LOG_GUEST_ERROR,
 | 
			
		||||
                      "sd_write_data: not in Receiving-Data state\n");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -1569,6 +1686,14 @@ void sd_write_data(SDState *sd, uint8_t value)
 | 
			
		||||
            sd->csd[14] |= 0x40;
 | 
			
		||||
 | 
			
		||||
            /* Bzzzzzzztt .... Operation complete.  */
 | 
			
		||||
            if (sd->multi_blk_cnt != 0) {
 | 
			
		||||
                if (--sd->multi_blk_cnt == 0) {
 | 
			
		||||
                    /* Stop! */
 | 
			
		||||
                    sd->state = sd_transfer_state;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            sd->state = sd_receivingdata_state;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
@ -1636,7 +1761,7 @@ void sd_write_data(SDState *sd, uint8_t value)
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
        fprintf(stderr, "sd_write_data: unknown command\n");
 | 
			
		||||
        qemu_log_mask(LOG_GUEST_ERROR, "sd_write_data: unknown command\n");
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1651,7 +1776,8 @@ uint8_t sd_read_data(SDState *sd)
 | 
			
		||||
        return 0x00;
 | 
			
		||||
 | 
			
		||||
    if (sd->state != sd_sendingdata_state) {
 | 
			
		||||
        fprintf(stderr, "sd_read_data: not in Sending-Data state\n");
 | 
			
		||||
        qemu_log_mask(LOG_GUEST_ERROR,
 | 
			
		||||
                      "sd_read_data: not in Sending-Data state\n");
 | 
			
		||||
        return 0x00;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -1715,6 +1841,15 @@ uint8_t sd_read_data(SDState *sd)
 | 
			
		||||
        if (sd->data_offset >= io_len) {
 | 
			
		||||
            sd->data_start += io_len;
 | 
			
		||||
            sd->data_offset = 0;
 | 
			
		||||
 | 
			
		||||
            if (sd->multi_blk_cnt != 0) {
 | 
			
		||||
                if (--sd->multi_blk_cnt == 0) {
 | 
			
		||||
                    /* Stop! */
 | 
			
		||||
                    sd->state = sd_transfer_state;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (sd->data_start + io_len > sd->size) {
 | 
			
		||||
                sd->card_status |= ADDRESS_ERROR;
 | 
			
		||||
                break;
 | 
			
		||||
@ -1753,7 +1888,7 @@ uint8_t sd_read_data(SDState *sd)
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
        fprintf(stderr, "sd_read_data: unknown command\n");
 | 
			
		||||
        qemu_log_mask(LOG_GUEST_ERROR, "sd_read_data: unknown command\n");
 | 
			
		||||
        return 0x00;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -1769,3 +1904,73 @@ void sd_enable(SDState *sd, bool enable)
 | 
			
		||||
{
 | 
			
		||||
    sd->enable = enable;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void sd_instance_init(Object *obj)
 | 
			
		||||
{
 | 
			
		||||
    SDState *sd = SD_CARD(obj);
 | 
			
		||||
 | 
			
		||||
    sd->enable = true;
 | 
			
		||||
    sd->ocr_power_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sd_ocr_powerup, sd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void sd_realize(DeviceState *dev, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    SDState *sd = SD_CARD(dev);
 | 
			
		||||
 | 
			
		||||
    if (sd->blk && blk_is_read_only(sd->blk)) {
 | 
			
		||||
        error_setg(errp, "Cannot use read-only drive as SD card");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sd->buf = blk_blockalign(sd->blk, 512);
 | 
			
		||||
 | 
			
		||||
    if (sd->blk) {
 | 
			
		||||
        blk_set_dev_ops(sd->blk, &sd_block_ops, sd);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static Property sd_properties[] = {
 | 
			
		||||
    DEFINE_PROP_DRIVE("drive", SDState, blk),
 | 
			
		||||
    /* We do not model the chip select pin, so allow the board to select
 | 
			
		||||
     * whether card should be in SSI or MMC/SD mode.  It is also up to the
 | 
			
		||||
     * board to ensure that ssi transfers only occur when the chip select
 | 
			
		||||
     * is asserted.  */
 | 
			
		||||
    DEFINE_PROP_BOOL("spi", SDState, spi, false),
 | 
			
		||||
    DEFINE_PROP_END_OF_LIST()
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void sd_class_init(ObjectClass *klass, void *data)
 | 
			
		||||
{
 | 
			
		||||
    DeviceClass *dc = DEVICE_CLASS(klass);
 | 
			
		||||
    SDCardClass *sc = SD_CARD_CLASS(klass);
 | 
			
		||||
 | 
			
		||||
    dc->realize = sd_realize;
 | 
			
		||||
    dc->props = sd_properties;
 | 
			
		||||
    dc->vmsd = &sd_vmstate;
 | 
			
		||||
    dc->reset = sd_reset;
 | 
			
		||||
    dc->bus_type = TYPE_SD_BUS;
 | 
			
		||||
 | 
			
		||||
    sc->do_command = sd_do_command;
 | 
			
		||||
    sc->write_data = sd_write_data;
 | 
			
		||||
    sc->read_data = sd_read_data;
 | 
			
		||||
    sc->data_ready = sd_data_ready;
 | 
			
		||||
    sc->enable = sd_enable;
 | 
			
		||||
    sc->get_inserted = sd_get_inserted;
 | 
			
		||||
    sc->get_readonly = sd_get_readonly;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const TypeInfo sd_info = {
 | 
			
		||||
    .name = TYPE_SD_CARD,
 | 
			
		||||
    .parent = TYPE_DEVICE,
 | 
			
		||||
    .instance_size = sizeof(SDState),
 | 
			
		||||
    .class_size = sizeof(SDCardClass),
 | 
			
		||||
    .class_init = sd_class_init,
 | 
			
		||||
    .instance_init = sd_instance_init,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void sd_register_types(void)
 | 
			
		||||
{
 | 
			
		||||
    type_register_static(&sd_info);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type_init(sd_register_types)
 | 
			
		||||
 | 
			
		||||
@ -55,6 +55,9 @@
 | 
			
		||||
        } \
 | 
			
		||||
    } while (0)
 | 
			
		||||
 | 
			
		||||
#define TYPE_SDHCI_BUS "sdhci-bus"
 | 
			
		||||
#define SDHCI_BUS(obj) OBJECT_CHECK(SDBus, (obj), TYPE_SDHCI_BUS)
 | 
			
		||||
 | 
			
		||||
/* Default SD/MMC host controller features information, which will be
 | 
			
		||||
 * presented in CAPABILITIES register of generic SD host controller at reset.
 | 
			
		||||
 * If not stated otherwise:
 | 
			
		||||
@ -145,9 +148,9 @@ static void sdhci_raise_insertion_irq(void *opaque)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void sdhci_insert_eject_cb(void *opaque, int irq, int level)
 | 
			
		||||
static void sdhci_set_inserted(DeviceState *dev, bool level)
 | 
			
		||||
{
 | 
			
		||||
    SDHCIState *s = (SDHCIState *)opaque;
 | 
			
		||||
    SDHCIState *s = (SDHCIState *)dev;
 | 
			
		||||
    DPRINT_L1("Card state changed: %s!\n", level ? "insert" : "eject");
 | 
			
		||||
 | 
			
		||||
    if ((s->norintsts & SDHC_NIS_REMOVE) && level) {
 | 
			
		||||
@ -172,9 +175,9 @@ static void sdhci_insert_eject_cb(void *opaque, int irq, int level)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void sdhci_card_readonly_cb(void *opaque, int irq, int level)
 | 
			
		||||
static void sdhci_set_readonly(DeviceState *dev, bool level)
 | 
			
		||||
{
 | 
			
		||||
    SDHCIState *s = (SDHCIState *)opaque;
 | 
			
		||||
    SDHCIState *s = (SDHCIState *)dev;
 | 
			
		||||
 | 
			
		||||
    if (level) {
 | 
			
		||||
        s->prnsts &= ~SDHC_WRITE_PROTECT;
 | 
			
		||||
@ -186,6 +189,8 @@ static void sdhci_card_readonly_cb(void *opaque, int irq, int level)
 | 
			
		||||
 | 
			
		||||
static void sdhci_reset(SDHCIState *s)
 | 
			
		||||
{
 | 
			
		||||
    DeviceState *dev = DEVICE(s);
 | 
			
		||||
 | 
			
		||||
    timer_del(s->insert_timer);
 | 
			
		||||
    timer_del(s->transfer_timer);
 | 
			
		||||
    /* Set all registers to 0. Capabilities registers are not cleared
 | 
			
		||||
@ -194,8 +199,11 @@ static void sdhci_reset(SDHCIState *s)
 | 
			
		||||
    memset(&s->sdmasysad, 0, (uintptr_t)&s->capareg - (uintptr_t)&s->sdmasysad);
 | 
			
		||||
 | 
			
		||||
    if (!s->noeject_quirk) {
 | 
			
		||||
        sd_set_cb(s->card, s->ro_cb, s->eject_cb);
 | 
			
		||||
        /* Reset other state based on current card insertion/readonly status */
 | 
			
		||||
        sdhci_set_inserted(dev, sdbus_get_inserted(&s->sdbus));
 | 
			
		||||
        sdhci_set_readonly(dev, sdbus_get_readonly(&s->sdbus));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    s->data_count = 0;
 | 
			
		||||
    s->stopped_state = sdhc_not_stopped;
 | 
			
		||||
}
 | 
			
		||||
@ -213,7 +221,7 @@ static void sdhci_send_command(SDHCIState *s)
 | 
			
		||||
    request.cmd = s->cmdreg >> 8;
 | 
			
		||||
    request.arg = s->argument;
 | 
			
		||||
    DPRINT_L1("sending CMD%u ARG[0x%08x]\n", request.cmd, request.arg);
 | 
			
		||||
    rlen = sd_do_command(s->card, &request, response);
 | 
			
		||||
    rlen = sdbus_do_command(&s->sdbus, &request, response);
 | 
			
		||||
 | 
			
		||||
    if (s->cmdreg & SDHC_CMD_RESPONSE) {
 | 
			
		||||
        if (rlen == 4) {
 | 
			
		||||
@ -269,7 +277,7 @@ static void sdhci_end_transfer(SDHCIState *s)
 | 
			
		||||
        request.cmd = 0x0C;
 | 
			
		||||
        request.arg = 0;
 | 
			
		||||
        DPRINT_L1("Automatically issue CMD%d %08x\n", request.cmd, request.arg);
 | 
			
		||||
        sd_do_command(s->card, &request, response);
 | 
			
		||||
        sdbus_do_command(&s->sdbus, &request, response);
 | 
			
		||||
        /* Auto CMD12 response goes to the upper Response register */
 | 
			
		||||
        s->rspreg[3] = (response[0] << 24) | (response[1] << 16) |
 | 
			
		||||
                (response[2] << 8) | response[3];
 | 
			
		||||
@ -301,7 +309,7 @@ static void sdhci_read_block_from_card(SDHCIState *s)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (index = 0; index < (s->blksize & 0x0fff); index++) {
 | 
			
		||||
        s->fifo_buffer[index] = sd_read_data(s->card);
 | 
			
		||||
        s->fifo_buffer[index] = sdbus_read_data(&s->sdbus);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* New data now available for READ through Buffer Port Register */
 | 
			
		||||
@ -394,7 +402,7 @@ static void sdhci_write_block_to_card(SDHCIState *s)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (index = 0; index < (s->blksize & 0x0fff); index++) {
 | 
			
		||||
        sd_write_data(s->card, s->fifo_buffer[index]);
 | 
			
		||||
        sdbus_write_data(&s->sdbus, s->fifo_buffer[index]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Next data can be written through BUFFER DATORT register */
 | 
			
		||||
@ -476,7 +484,7 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
 | 
			
		||||
        while (s->blkcnt) {
 | 
			
		||||
            if (s->data_count == 0) {
 | 
			
		||||
                for (n = 0; n < block_size; n++) {
 | 
			
		||||
                    s->fifo_buffer[n] = sd_read_data(s->card);
 | 
			
		||||
                    s->fifo_buffer[n] = sdbus_read_data(&s->sdbus);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            begin = s->data_count;
 | 
			
		||||
@ -517,7 +525,7 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
 | 
			
		||||
            s->sdmasysad += s->data_count - begin;
 | 
			
		||||
            if (s->data_count == block_size) {
 | 
			
		||||
                for (n = 0; n < block_size; n++) {
 | 
			
		||||
                    sd_write_data(s->card, s->fifo_buffer[n]);
 | 
			
		||||
                    sdbus_write_data(&s->sdbus, s->fifo_buffer[n]);
 | 
			
		||||
                }
 | 
			
		||||
                s->data_count = 0;
 | 
			
		||||
                if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) {
 | 
			
		||||
@ -549,7 +557,7 @@ static void sdhci_sdma_transfer_single_block(SDHCIState *s)
 | 
			
		||||
 | 
			
		||||
    if (s->trnmod & SDHC_TRNS_READ) {
 | 
			
		||||
        for (n = 0; n < datacnt; n++) {
 | 
			
		||||
            s->fifo_buffer[n] = sd_read_data(s->card);
 | 
			
		||||
            s->fifo_buffer[n] = sdbus_read_data(&s->sdbus);
 | 
			
		||||
        }
 | 
			
		||||
        dma_memory_write(&address_space_memory, s->sdmasysad, s->fifo_buffer,
 | 
			
		||||
                         datacnt);
 | 
			
		||||
@ -557,7 +565,7 @@ static void sdhci_sdma_transfer_single_block(SDHCIState *s)
 | 
			
		||||
        dma_memory_read(&address_space_memory, s->sdmasysad, s->fifo_buffer,
 | 
			
		||||
                        datacnt);
 | 
			
		||||
        for (n = 0; n < datacnt; n++) {
 | 
			
		||||
            sd_write_data(s->card, s->fifo_buffer[n]);
 | 
			
		||||
            sdbus_write_data(&s->sdbus, s->fifo_buffer[n]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -661,7 +669,7 @@ static void sdhci_do_adma(SDHCIState *s)
 | 
			
		||||
                while (length) {
 | 
			
		||||
                    if (s->data_count == 0) {
 | 
			
		||||
                        for (n = 0; n < block_size; n++) {
 | 
			
		||||
                            s->fifo_buffer[n] = sd_read_data(s->card);
 | 
			
		||||
                            s->fifo_buffer[n] = sdbus_read_data(&s->sdbus);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    begin = s->data_count;
 | 
			
		||||
@ -702,7 +710,7 @@ static void sdhci_do_adma(SDHCIState *s)
 | 
			
		||||
                    dscr.addr += s->data_count - begin;
 | 
			
		||||
                    if (s->data_count == block_size) {
 | 
			
		||||
                        for (n = 0; n < block_size; n++) {
 | 
			
		||||
                            sd_write_data(s->card, s->fifo_buffer[n]);
 | 
			
		||||
                            sdbus_write_data(&s->sdbus, s->fifo_buffer[n]);
 | 
			
		||||
                        }
 | 
			
		||||
                        s->data_count = 0;
 | 
			
		||||
                        if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) {
 | 
			
		||||
@ -816,7 +824,7 @@ static void sdhci_data_transfer(void *opaque)
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        if ((s->trnmod & SDHC_TRNS_READ) && sd_data_ready(s->card)) {
 | 
			
		||||
        if ((s->trnmod & SDHC_TRNS_READ) && sdbus_data_ready(&s->sdbus)) {
 | 
			
		||||
            s->prnsts |= SDHC_DOING_READ | SDHC_DATA_INHIBIT |
 | 
			
		||||
                    SDHC_DAT_LINE_ACTIVE;
 | 
			
		||||
            sdhci_read_block_from_card(s);
 | 
			
		||||
@ -1153,15 +1161,10 @@ static inline unsigned int sdhci_get_fifolen(SDHCIState *s)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void sdhci_initfn(SDHCIState *s, BlockBackend *blk)
 | 
			
		||||
static void sdhci_initfn(SDHCIState *s)
 | 
			
		||||
{
 | 
			
		||||
    s->card = sd_init(blk, false);
 | 
			
		||||
    if (s->card == NULL) {
 | 
			
		||||
        exit(1);
 | 
			
		||||
    }
 | 
			
		||||
    s->eject_cb = qemu_allocate_irq(sdhci_insert_eject_cb, s, 0);
 | 
			
		||||
    s->ro_cb = qemu_allocate_irq(sdhci_card_readonly_cb, s, 0);
 | 
			
		||||
    sd_set_cb(s->card, s->ro_cb, s->eject_cb);
 | 
			
		||||
    qbus_create_inplace(&s->sdbus, sizeof(s->sdbus),
 | 
			
		||||
                        TYPE_SDHCI_BUS, DEVICE(s), "sd-bus");
 | 
			
		||||
 | 
			
		||||
    s->insert_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_raise_insertion_irq, s);
 | 
			
		||||
    s->transfer_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sdhci_data_transfer, s);
 | 
			
		||||
@ -1220,12 +1223,6 @@ const VMStateDescription sdhci_vmstate = {
 | 
			
		||||
/* Capabilities registers provide information on supported features of this
 | 
			
		||||
 * specific host controller implementation */
 | 
			
		||||
static Property sdhci_pci_properties[] = {
 | 
			
		||||
    /*
 | 
			
		||||
     * We currently fuse controller and card into a single device
 | 
			
		||||
     * model, but we intend to separate them.  For that purpose, the
 | 
			
		||||
     * properties that belong to the card are marked as experimental.
 | 
			
		||||
     */
 | 
			
		||||
    DEFINE_PROP_DRIVE("x-drive", SDHCIState, blk),
 | 
			
		||||
    DEFINE_PROP_UINT32("capareg", SDHCIState, capareg,
 | 
			
		||||
            SDHC_CAPAB_REG_DEFAULT),
 | 
			
		||||
    DEFINE_PROP_UINT32("maxcurr", SDHCIState, maxcurr, 0),
 | 
			
		||||
@ -1237,7 +1234,7 @@ static void sdhci_pci_realize(PCIDevice *dev, Error **errp)
 | 
			
		||||
    SDHCIState *s = PCI_SDHCI(dev);
 | 
			
		||||
    dev->config[PCI_CLASS_PROG] = 0x01; /* Standard Host supported DMA */
 | 
			
		||||
    dev->config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
 | 
			
		||||
    sdhci_initfn(s, s->blk);
 | 
			
		||||
    sdhci_initfn(s);
 | 
			
		||||
    s->buf_maxsz = sdhci_get_fifolen(s);
 | 
			
		||||
    s->fifo_buffer = g_malloc0(s->buf_maxsz);
 | 
			
		||||
    s->irq = pci_allocate_irq(dev);
 | 
			
		||||
@ -1285,11 +1282,8 @@ static Property sdhci_sysbus_properties[] = {
 | 
			
		||||
static void sdhci_sysbus_init(Object *obj)
 | 
			
		||||
{
 | 
			
		||||
    SDHCIState *s = SYSBUS_SDHCI(obj);
 | 
			
		||||
    DriveInfo *di;
 | 
			
		||||
 | 
			
		||||
    /* FIXME use a qdev drive property instead of drive_get_next() */
 | 
			
		||||
    di = drive_get_next(IF_SD);
 | 
			
		||||
    sdhci_initfn(s, di ? blk_by_legacy_dinfo(di) : NULL);
 | 
			
		||||
    sdhci_initfn(s);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void sdhci_sysbus_finalize(Object *obj)
 | 
			
		||||
@ -1318,8 +1312,6 @@ static void sdhci_sysbus_class_init(ObjectClass *klass, void *data)
 | 
			
		||||
    dc->vmsd = &sdhci_vmstate;
 | 
			
		||||
    dc->props = sdhci_sysbus_properties;
 | 
			
		||||
    dc->realize = sdhci_sysbus_realize;
 | 
			
		||||
    /* Reason: instance_init() method uses drive_get_next() */
 | 
			
		||||
    dc->cannot_instantiate_with_device_add_yet = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const TypeInfo sdhci_sysbus_info = {
 | 
			
		||||
@ -1331,10 +1323,26 @@ static const TypeInfo sdhci_sysbus_info = {
 | 
			
		||||
    .class_init = sdhci_sysbus_class_init,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void sdhci_bus_class_init(ObjectClass *klass, void *data)
 | 
			
		||||
{
 | 
			
		||||
    SDBusClass *sbc = SD_BUS_CLASS(klass);
 | 
			
		||||
 | 
			
		||||
    sbc->set_inserted = sdhci_set_inserted;
 | 
			
		||||
    sbc->set_readonly = sdhci_set_readonly;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const TypeInfo sdhci_bus_info = {
 | 
			
		||||
    .name = TYPE_SDHCI_BUS,
 | 
			
		||||
    .parent = TYPE_SD_BUS,
 | 
			
		||||
    .instance_size = sizeof(SDBus),
 | 
			
		||||
    .class_init = sdhci_bus_class_init,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void sdhci_register_types(void)
 | 
			
		||||
{
 | 
			
		||||
    type_register_static(&sdhci_pci_info);
 | 
			
		||||
    type_register_static(&sdhci_sysbus_info);
 | 
			
		||||
    type_register_static(&sdhci_bus_info);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type_init(sdhci_register_types)
 | 
			
		||||
 | 
			
		||||
@ -277,21 +277,25 @@ static const VMStateDescription vmstate_sp804 = {
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int sp804_init(SysBusDevice *sbd)
 | 
			
		||||
static void sp804_init(Object *obj)
 | 
			
		||||
{
 | 
			
		||||
    DeviceState *dev = DEVICE(sbd);
 | 
			
		||||
    SP804State *s = SP804(dev);
 | 
			
		||||
    SP804State *s = SP804(obj);
 | 
			
		||||
    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 | 
			
		||||
 | 
			
		||||
    sysbus_init_irq(sbd, &s->irq);
 | 
			
		||||
    memory_region_init_io(&s->iomem, obj, &sp804_ops, s,
 | 
			
		||||
                          "sp804", 0x1000);
 | 
			
		||||
    sysbus_init_mmio(sbd, &s->iomem);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void sp804_realize(DeviceState *dev, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    SP804State *s = SP804(dev);
 | 
			
		||||
 | 
			
		||||
    s->timer[0] = arm_timer_init(s->freq0);
 | 
			
		||||
    s->timer[1] = arm_timer_init(s->freq1);
 | 
			
		||||
    s->timer[0]->irq = qemu_allocate_irq(sp804_set_irq, s, 0);
 | 
			
		||||
    s->timer[1]->irq = qemu_allocate_irq(sp804_set_irq, s, 1);
 | 
			
		||||
    memory_region_init_io(&s->iomem, OBJECT(s), &sp804_ops, s,
 | 
			
		||||
                          "sp804", 0x1000);
 | 
			
		||||
    sysbus_init_mmio(sbd, &s->iomem);
 | 
			
		||||
    vmstate_register(dev, -1, &vmstate_sp804, s);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Integrator/CP timer module.  */
 | 
			
		||||
@ -344,9 +348,10 @@ static const MemoryRegionOps icp_pit_ops = {
 | 
			
		||||
    .endianness = DEVICE_NATIVE_ENDIAN,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int icp_pit_init(SysBusDevice *dev)
 | 
			
		||||
static void icp_pit_init(Object *obj)
 | 
			
		||||
{
 | 
			
		||||
    icp_pit_state *s = INTEGRATOR_PIT(dev);
 | 
			
		||||
    icp_pit_state *s = INTEGRATOR_PIT(obj);
 | 
			
		||||
    SysBusDevice *dev = SYS_BUS_DEVICE(obj);
 | 
			
		||||
 | 
			
		||||
    /* Timer 0 runs at the system clock speed (40MHz).  */
 | 
			
		||||
    s->timer[0] = arm_timer_init(40000000);
 | 
			
		||||
@ -358,26 +363,18 @@ static int icp_pit_init(SysBusDevice *dev)
 | 
			
		||||
    sysbus_init_irq(dev, &s->timer[1]->irq);
 | 
			
		||||
    sysbus_init_irq(dev, &s->timer[2]->irq);
 | 
			
		||||
 | 
			
		||||
    memory_region_init_io(&s->iomem, OBJECT(s), &icp_pit_ops, s,
 | 
			
		||||
    memory_region_init_io(&s->iomem, obj, &icp_pit_ops, s,
 | 
			
		||||
                          "icp_pit", 0x1000);
 | 
			
		||||
    sysbus_init_mmio(dev, &s->iomem);
 | 
			
		||||
    /* This device has no state to save/restore.  The component timers will
 | 
			
		||||
       save themselves.  */
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void icp_pit_class_init(ObjectClass *klass, void *data)
 | 
			
		||||
{
 | 
			
		||||
    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
 | 
			
		||||
 | 
			
		||||
    sdc->init = icp_pit_init;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const TypeInfo icp_pit_info = {
 | 
			
		||||
    .name          = TYPE_INTEGRATOR_PIT,
 | 
			
		||||
    .parent        = TYPE_SYS_BUS_DEVICE,
 | 
			
		||||
    .instance_size = sizeof(icp_pit_state),
 | 
			
		||||
    .class_init    = icp_pit_class_init,
 | 
			
		||||
    .instance_init = icp_pit_init,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static Property sp804_properties[] = {
 | 
			
		||||
@ -388,17 +385,18 @@ static Property sp804_properties[] = {
 | 
			
		||||
 | 
			
		||||
static void sp804_class_init(ObjectClass *klass, void *data)
 | 
			
		||||
{
 | 
			
		||||
    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
 | 
			
		||||
    DeviceClass *k = DEVICE_CLASS(klass);
 | 
			
		||||
 | 
			
		||||
    sdc->init = sp804_init;
 | 
			
		||||
    k->realize = sp804_realize;
 | 
			
		||||
    k->props = sp804_properties;
 | 
			
		||||
    k->vmsd = &vmstate_sp804;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const TypeInfo sp804_info = {
 | 
			
		||||
    .name          = TYPE_SP804,
 | 
			
		||||
    .parent        = TYPE_SYS_BUS_DEVICE,
 | 
			
		||||
    .instance_size = sizeof(SP804State),
 | 
			
		||||
    .instance_init = sp804_init,
 | 
			
		||||
    .class_init    = sp804_class_init,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1422,10 +1422,11 @@ static const MemoryRegionOps exynos4210_mct_ops = {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* MCT init */
 | 
			
		||||
static int exynos4210_mct_init(SysBusDevice *dev)
 | 
			
		||||
static void exynos4210_mct_init(Object *obj)
 | 
			
		||||
{
 | 
			
		||||
    int i;
 | 
			
		||||
    Exynos4210MCTState *s = EXYNOS4210_MCT(dev);
 | 
			
		||||
    Exynos4210MCTState *s = EXYNOS4210_MCT(obj);
 | 
			
		||||
    SysBusDevice *dev = SYS_BUS_DEVICE(obj);
 | 
			
		||||
    QEMUBH *bh[2];
 | 
			
		||||
 | 
			
		||||
    /* Global timer */
 | 
			
		||||
@ -1450,19 +1451,15 @@ static int exynos4210_mct_init(SysBusDevice *dev)
 | 
			
		||||
        sysbus_init_irq(dev, &s->l_timer[i].irq);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_mct_ops, s,
 | 
			
		||||
    memory_region_init_io(&s->iomem, obj, &exynos4210_mct_ops, s,
 | 
			
		||||
                          "exynos4210-mct", MCT_SFR_SIZE);
 | 
			
		||||
    sysbus_init_mmio(dev, &s->iomem);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void exynos4210_mct_class_init(ObjectClass *klass, void *data)
 | 
			
		||||
{
 | 
			
		||||
    DeviceClass *dc = DEVICE_CLASS(klass);
 | 
			
		||||
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 | 
			
		||||
 | 
			
		||||
    k->init = exynos4210_mct_init;
 | 
			
		||||
    dc->reset = exynos4210_mct_reset;
 | 
			
		||||
    dc->vmsd = &vmstate_exynos4210_mct_state;
 | 
			
		||||
}
 | 
			
		||||
@ -1471,6 +1468,7 @@ static const TypeInfo exynos4210_mct_info = {
 | 
			
		||||
    .name          = TYPE_EXYNOS4210_MCT,
 | 
			
		||||
    .parent        = TYPE_SYS_BUS_DEVICE,
 | 
			
		||||
    .instance_size = sizeof(Exynos4210MCTState),
 | 
			
		||||
    .instance_init = exynos4210_mct_init,
 | 
			
		||||
    .class_init    = exynos4210_mct_class_init,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -380,9 +380,10 @@ static const MemoryRegionOps exynos4210_pwm_ops = {
 | 
			
		||||
/*
 | 
			
		||||
 * PWM timer initialization
 | 
			
		||||
 */
 | 
			
		||||
static int exynos4210_pwm_init(SysBusDevice *dev)
 | 
			
		||||
static void exynos4210_pwm_init(Object *obj)
 | 
			
		||||
{
 | 
			
		||||
    Exynos4210PWMState *s = EXYNOS4210_PWM(dev);
 | 
			
		||||
    Exynos4210PWMState *s = EXYNOS4210_PWM(obj);
 | 
			
		||||
    SysBusDevice *dev = SYS_BUS_DEVICE(obj);
 | 
			
		||||
    int i;
 | 
			
		||||
    QEMUBH *bh;
 | 
			
		||||
 | 
			
		||||
@ -394,19 +395,15 @@ static int exynos4210_pwm_init(SysBusDevice *dev)
 | 
			
		||||
        s->timer[i].parent = s;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_pwm_ops, s,
 | 
			
		||||
    memory_region_init_io(&s->iomem, obj, &exynos4210_pwm_ops, s,
 | 
			
		||||
                          "exynos4210-pwm", EXYNOS4210_PWM_REG_MEM_SIZE);
 | 
			
		||||
    sysbus_init_mmio(dev, &s->iomem);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void exynos4210_pwm_class_init(ObjectClass *klass, void *data)
 | 
			
		||||
{
 | 
			
		||||
    DeviceClass *dc = DEVICE_CLASS(klass);
 | 
			
		||||
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 | 
			
		||||
 | 
			
		||||
    k->init = exynos4210_pwm_init;
 | 
			
		||||
    dc->reset = exynos4210_pwm_reset;
 | 
			
		||||
    dc->vmsd = &vmstate_exynos4210_pwm_state;
 | 
			
		||||
}
 | 
			
		||||
@ -415,6 +412,7 @@ static const TypeInfo exynos4210_pwm_info = {
 | 
			
		||||
    .name          = TYPE_EXYNOS4210_PWM,
 | 
			
		||||
    .parent        = TYPE_SYS_BUS_DEVICE,
 | 
			
		||||
    .instance_size = sizeof(Exynos4210PWMState),
 | 
			
		||||
    .instance_init = exynos4210_pwm_init,
 | 
			
		||||
    .class_init    = exynos4210_pwm_class_init,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -547,9 +547,10 @@ static const MemoryRegionOps exynos4210_rtc_ops = {
 | 
			
		||||
/*
 | 
			
		||||
 * RTC timer initialization
 | 
			
		||||
 */
 | 
			
		||||
static int exynos4210_rtc_init(SysBusDevice *dev)
 | 
			
		||||
static void exynos4210_rtc_init(Object *obj)
 | 
			
		||||
{
 | 
			
		||||
    Exynos4210RTCState *s = EXYNOS4210_RTC(dev);
 | 
			
		||||
    Exynos4210RTCState *s = EXYNOS4210_RTC(obj);
 | 
			
		||||
    SysBusDevice *dev = SYS_BUS_DEVICE(obj);
 | 
			
		||||
    QEMUBH *bh;
 | 
			
		||||
 | 
			
		||||
    bh = qemu_bh_new(exynos4210_rtc_tick, s);
 | 
			
		||||
@ -564,19 +565,15 @@ static int exynos4210_rtc_init(SysBusDevice *dev)
 | 
			
		||||
    sysbus_init_irq(dev, &s->alm_irq);
 | 
			
		||||
    sysbus_init_irq(dev, &s->tick_irq);
 | 
			
		||||
 | 
			
		||||
    memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_rtc_ops, s,
 | 
			
		||||
    memory_region_init_io(&s->iomem, obj, &exynos4210_rtc_ops, s,
 | 
			
		||||
                          "exynos4210-rtc", EXYNOS4210_RTC_REG_MEM_SIZE);
 | 
			
		||||
    sysbus_init_mmio(dev, &s->iomem);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void exynos4210_rtc_class_init(ObjectClass *klass, void *data)
 | 
			
		||||
{
 | 
			
		||||
    DeviceClass *dc = DEVICE_CLASS(klass);
 | 
			
		||||
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 | 
			
		||||
 | 
			
		||||
    k->init = exynos4210_rtc_init;
 | 
			
		||||
    dc->reset = exynos4210_rtc_reset;
 | 
			
		||||
    dc->vmsd = &vmstate_exynos4210_rtc_state;
 | 
			
		||||
}
 | 
			
		||||
@ -585,6 +582,7 @@ static const TypeInfo exynos4210_rtc_info = {
 | 
			
		||||
    .name          = TYPE_EXYNOS4210_RTC,
 | 
			
		||||
    .parent        = TYPE_SYS_BUS_DEVICE,
 | 
			
		||||
    .instance_size = sizeof(Exynos4210RTCState),
 | 
			
		||||
    .instance_init = exynos4210_rtc_init,
 | 
			
		||||
    .class_init    = exynos4210_rtc_class_init,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -192,12 +192,13 @@ static const MemoryRegionOps pl031_ops = {
 | 
			
		||||
    .endianness = DEVICE_NATIVE_ENDIAN,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int pl031_init(SysBusDevice *dev)
 | 
			
		||||
static void pl031_init(Object *obj)
 | 
			
		||||
{
 | 
			
		||||
    PL031State *s = PL031(dev);
 | 
			
		||||
    PL031State *s = PL031(obj);
 | 
			
		||||
    SysBusDevice *dev = SYS_BUS_DEVICE(obj);
 | 
			
		||||
    struct tm tm;
 | 
			
		||||
 | 
			
		||||
    memory_region_init_io(&s->iomem, OBJECT(s), &pl031_ops, s, "pl031", 0x1000);
 | 
			
		||||
    memory_region_init_io(&s->iomem, obj, &pl031_ops, s, "pl031", 0x1000);
 | 
			
		||||
    sysbus_init_mmio(dev, &s->iomem);
 | 
			
		||||
 | 
			
		||||
    sysbus_init_irq(dev, &s->irq);
 | 
			
		||||
@ -206,7 +207,6 @@ static int pl031_init(SysBusDevice *dev)
 | 
			
		||||
        qemu_clock_get_ns(rtc_clock) / get_ticks_per_sec();
 | 
			
		||||
 | 
			
		||||
    s->timer = timer_new_ns(rtc_clock, pl031_interrupt, s);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void pl031_pre_save(void *opaque)
 | 
			
		||||
@ -249,9 +249,7 @@ static const VMStateDescription vmstate_pl031 = {
 | 
			
		||||
static void pl031_class_init(ObjectClass *klass, void *data)
 | 
			
		||||
{
 | 
			
		||||
    DeviceClass *dc = DEVICE_CLASS(klass);
 | 
			
		||||
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 | 
			
		||||
 | 
			
		||||
    k->init = pl031_init;
 | 
			
		||||
    dc->vmsd = &vmstate_pl031;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -259,6 +257,7 @@ static const TypeInfo pl031_info = {
 | 
			
		||||
    .name          = TYPE_PL031,
 | 
			
		||||
    .parent        = TYPE_SYS_BUS_DEVICE,
 | 
			
		||||
    .instance_size = sizeof(PL031State),
 | 
			
		||||
    .instance_init = pl031_init,
 | 
			
		||||
    .class_init    = pl031_class_init,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -433,10 +433,10 @@ static int pxa25x_timer_post_load(void *opaque, int version_id)
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int pxa2xx_timer_init(SysBusDevice *dev)
 | 
			
		||||
static void pxa2xx_timer_init(Object *obj)
 | 
			
		||||
{
 | 
			
		||||
    PXA2xxTimerInfo *s = PXA2XX_TIMER(dev);
 | 
			
		||||
    int i;
 | 
			
		||||
    PXA2xxTimerInfo *s = PXA2XX_TIMER(obj);
 | 
			
		||||
    SysBusDevice *dev = SYS_BUS_DEVICE(obj);
 | 
			
		||||
 | 
			
		||||
    s->irq_enabled = 0;
 | 
			
		||||
    s->oldclock = 0;
 | 
			
		||||
@ -444,16 +444,28 @@ static int pxa2xx_timer_init(SysBusDevice *dev)
 | 
			
		||||
    s->lastload = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
 | 
			
		||||
    s->reset3 = 0;
 | 
			
		||||
 | 
			
		||||
    memory_region_init_io(&s->iomem, obj, &pxa2xx_timer_ops, s,
 | 
			
		||||
                          "pxa2xx-timer", 0x00001000);
 | 
			
		||||
    sysbus_init_mmio(dev, &s->iomem);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void pxa2xx_timer_realize(DeviceState *dev, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    PXA2xxTimerInfo *s = PXA2XX_TIMER(dev);
 | 
			
		||||
    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < 4; i ++) {
 | 
			
		||||
        s->timer[i].value = 0;
 | 
			
		||||
        sysbus_init_irq(dev, &s->timer[i].irq);
 | 
			
		||||
        sysbus_init_irq(sbd, &s->timer[i].irq);
 | 
			
		||||
        s->timer[i].info = s;
 | 
			
		||||
        s->timer[i].num = i;
 | 
			
		||||
        s->timer[i].qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
 | 
			
		||||
                                          pxa2xx_timer_tick, &s->timer[i]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (s->flags & (1 << PXA2XX_TIMER_HAVE_TM4)) {
 | 
			
		||||
        sysbus_init_irq(dev, &s->irq4);
 | 
			
		||||
        sysbus_init_irq(sbd, &s->irq4);
 | 
			
		||||
 | 
			
		||||
        for (i = 0; i < 8; i ++) {
 | 
			
		||||
            s->tm4[i].tm.value = 0;
 | 
			
		||||
@ -465,12 +477,6 @@ static int pxa2xx_timer_init(SysBusDevice *dev)
 | 
			
		||||
                                               pxa2xx_timer_tick4, &s->tm4[i]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    memory_region_init_io(&s->iomem, OBJECT(s), &pxa2xx_timer_ops, s,
 | 
			
		||||
                          "pxa2xx-timer", 0x00001000);
 | 
			
		||||
    sysbus_init_mmio(dev, &s->iomem);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const VMStateDescription vmstate_pxa2xx_timer0_regs = {
 | 
			
		||||
@ -573,9 +579,8 @@ static const TypeInfo pxa27x_timer_dev_info = {
 | 
			
		||||
static void pxa2xx_timer_class_init(ObjectClass *oc, void *data)
 | 
			
		||||
{
 | 
			
		||||
    DeviceClass *dc = DEVICE_CLASS(oc);
 | 
			
		||||
    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(oc);
 | 
			
		||||
 | 
			
		||||
    sdc->init = pxa2xx_timer_init;
 | 
			
		||||
    dc->realize  = pxa2xx_timer_realize;
 | 
			
		||||
    dc->vmsd = &vmstate_pxa2xx_timer_regs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -583,6 +588,7 @@ static const TypeInfo pxa2xx_timer_type_info = {
 | 
			
		||||
    .name          = TYPE_PXA2XX_TIMER,
 | 
			
		||||
    .parent        = TYPE_SYS_BUS_DEVICE,
 | 
			
		||||
    .instance_size = sizeof(PXA2xxTimerInfo),
 | 
			
		||||
    .instance_init = pxa2xx_timer_init,
 | 
			
		||||
    .abstract      = true,
 | 
			
		||||
    .class_init    = pxa2xx_timer_class_init,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -67,7 +67,51 @@ typedef struct {
 | 
			
		||||
} SDRequest;
 | 
			
		||||
 | 
			
		||||
typedef struct SDState SDState;
 | 
			
		||||
typedef struct SDBus SDBus;
 | 
			
		||||
 | 
			
		||||
#define TYPE_SD_CARD "sd-card"
 | 
			
		||||
#define SD_CARD(obj) OBJECT_CHECK(SDState, (obj), TYPE_SD_CARD)
 | 
			
		||||
#define SD_CARD_CLASS(klass) \
 | 
			
		||||
    OBJECT_CLASS_CHECK(SDCardClass, (klass), TYPE_SD_CARD)
 | 
			
		||||
#define SD_CARD_GET_CLASS(obj) \
 | 
			
		||||
    OBJECT_GET_CLASS(SDCardClass, (obj), TYPE_SD_CARD)
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    /*< private >*/
 | 
			
		||||
    DeviceClass parent_class;
 | 
			
		||||
    /*< public >*/
 | 
			
		||||
 | 
			
		||||
    int (*do_command)(SDState *sd, SDRequest *req, uint8_t *response);
 | 
			
		||||
    void (*write_data)(SDState *sd, uint8_t value);
 | 
			
		||||
    uint8_t (*read_data)(SDState *sd);
 | 
			
		||||
    bool (*data_ready)(SDState *sd);
 | 
			
		||||
    void (*enable)(SDState *sd, bool enable);
 | 
			
		||||
    bool (*get_inserted)(SDState *sd);
 | 
			
		||||
    bool (*get_readonly)(SDState *sd);
 | 
			
		||||
} SDCardClass;
 | 
			
		||||
 | 
			
		||||
#define TYPE_SD_BUS "sd-bus"
 | 
			
		||||
#define SD_BUS(obj) OBJECT_CHECK(SDBus, (obj), TYPE_SD_BUS)
 | 
			
		||||
#define SD_BUS_CLASS(klass) OBJECT_CLASS_CHECK(SDBusClass, (klass), TYPE_SD_BUS)
 | 
			
		||||
#define SD_BUS_GET_CLASS(obj) OBJECT_GET_CLASS(SDBusClass, (obj), TYPE_SD_BUS)
 | 
			
		||||
 | 
			
		||||
struct SDBus {
 | 
			
		||||
    BusState qbus;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    /*< private >*/
 | 
			
		||||
    BusClass parent_class;
 | 
			
		||||
    /*< public >*/
 | 
			
		||||
 | 
			
		||||
    /* These methods are called by the SD device to notify the controller
 | 
			
		||||
     * when the card insertion or readonly status changes
 | 
			
		||||
     */
 | 
			
		||||
    void (*set_inserted)(DeviceState *dev, bool inserted);
 | 
			
		||||
    void (*set_readonly)(DeviceState *dev, bool readonly);
 | 
			
		||||
} SDBusClass;
 | 
			
		||||
 | 
			
		||||
/* Legacy functions to be used only by non-qdevified callers */
 | 
			
		||||
SDState *sd_init(BlockBackend *bs, bool is_spi);
 | 
			
		||||
int sd_do_command(SDState *sd, SDRequest *req,
 | 
			
		||||
                  uint8_t *response);
 | 
			
		||||
@ -75,6 +119,27 @@ void sd_write_data(SDState *sd, uint8_t value);
 | 
			
		||||
uint8_t sd_read_data(SDState *sd);
 | 
			
		||||
void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert);
 | 
			
		||||
bool sd_data_ready(SDState *sd);
 | 
			
		||||
/* sd_enable should not be used -- it is only used on the nseries boards,
 | 
			
		||||
 * where it is part of a broken implementation of the MMC card slot switch
 | 
			
		||||
 * (there should be two card slots which are multiplexed to a single MMC
 | 
			
		||||
 * controller, but instead we model it with one card and controller and
 | 
			
		||||
 * disable the card when the second slot is selected, so it looks like the
 | 
			
		||||
 * second slot is always empty).
 | 
			
		||||
 */
 | 
			
		||||
void sd_enable(SDState *sd, bool enable);
 | 
			
		||||
 | 
			
		||||
/* Functions to be used by qdevified callers (working via
 | 
			
		||||
 * an SDBus rather than directly with SDState)
 | 
			
		||||
 */
 | 
			
		||||
int sdbus_do_command(SDBus *sd, SDRequest *req, uint8_t *response);
 | 
			
		||||
void sdbus_write_data(SDBus *sd, uint8_t value);
 | 
			
		||||
uint8_t sdbus_read_data(SDBus *sd);
 | 
			
		||||
bool sdbus_data_ready(SDBus *sd);
 | 
			
		||||
bool sdbus_get_inserted(SDBus *sd);
 | 
			
		||||
bool sdbus_get_readonly(SDBus *sd);
 | 
			
		||||
 | 
			
		||||
/* Functions to be used by SD devices to report back to qdevified controllers */
 | 
			
		||||
void sdbus_set_inserted(SDBus *sd, bool inserted);
 | 
			
		||||
void sdbus_set_readonly(SDBus *sd, bool inserted);
 | 
			
		||||
 | 
			
		||||
#endif	/* __hw_sd_h */
 | 
			
		||||
 | 
			
		||||
@ -37,9 +37,8 @@ typedef struct SDHCIState {
 | 
			
		||||
        PCIDevice pcidev;
 | 
			
		||||
        SysBusDevice busdev;
 | 
			
		||||
    };
 | 
			
		||||
    SDState *card;
 | 
			
		||||
    SDBus sdbus;
 | 
			
		||||
    MemoryRegion iomem;
 | 
			
		||||
    BlockBackend *blk;
 | 
			
		||||
 | 
			
		||||
    QEMUTimer *insert_timer;       /* timer for 'changing' sd card. */
 | 
			
		||||
    QEMUTimer *transfer_timer;
 | 
			
		||||
 | 
			
		||||
@ -148,6 +148,8 @@ typedef struct ARMCPU {
 | 
			
		||||
    uint32_t id_pfr0;
 | 
			
		||||
    uint32_t id_pfr1;
 | 
			
		||||
    uint32_t id_dfr0;
 | 
			
		||||
    uint32_t pmceid0;
 | 
			
		||||
    uint32_t pmceid1;
 | 
			
		||||
    uint32_t id_afr0;
 | 
			
		||||
    uint32_t id_mmfr0;
 | 
			
		||||
    uint32_t id_mmfr1;
 | 
			
		||||
 | 
			
		||||
@ -1156,6 +1156,8 @@ static void cortex_a15_initfn(Object *obj)
 | 
			
		||||
    cpu->id_pfr0 = 0x00001131;
 | 
			
		||||
    cpu->id_pfr1 = 0x00011011;
 | 
			
		||||
    cpu->id_dfr0 = 0x02010555;
 | 
			
		||||
    cpu->pmceid0 = 0x0000000;
 | 
			
		||||
    cpu->pmceid1 = 0x00000000;
 | 
			
		||||
    cpu->id_afr0 = 0x00000000;
 | 
			
		||||
    cpu->id_mmfr0 = 0x10201105;
 | 
			
		||||
    cpu->id_mmfr1 = 0x20000000;
 | 
			
		||||
 | 
			
		||||
@ -595,6 +595,18 @@ void pmccntr_sync(CPUARMState *env);
 | 
			
		||||
#define CPTR_TTA      (1U << 20)
 | 
			
		||||
#define CPTR_TFP      (1U << 10)
 | 
			
		||||
 | 
			
		||||
#define MDCR_EPMAD    (1U << 21)
 | 
			
		||||
#define MDCR_EDAD     (1U << 20)
 | 
			
		||||
#define MDCR_SPME     (1U << 17)
 | 
			
		||||
#define MDCR_SDD      (1U << 16)
 | 
			
		||||
#define MDCR_TDRA     (1U << 11)
 | 
			
		||||
#define MDCR_TDOSA    (1U << 10)
 | 
			
		||||
#define MDCR_TDA      (1U << 9)
 | 
			
		||||
#define MDCR_TDE      (1U << 8)
 | 
			
		||||
#define MDCR_HPME     (1U << 7)
 | 
			
		||||
#define MDCR_TPM      (1U << 6)
 | 
			
		||||
#define MDCR_TPMCR    (1U << 5)
 | 
			
		||||
 | 
			
		||||
#define CPSR_M (0x1fU)
 | 
			
		||||
#define CPSR_T (1U << 5)
 | 
			
		||||
#define CPSR_F (1U << 6)
 | 
			
		||||
@ -1255,6 +1267,18 @@ static inline bool cptype_valid(int cptype)
 | 
			
		||||
#define PL1_RW (PL1_R | PL1_W)
 | 
			
		||||
#define PL0_RW (PL0_R | PL0_W)
 | 
			
		||||
 | 
			
		||||
/* Return the highest implemented Exception Level */
 | 
			
		||||
static inline int arm_highest_el(CPUARMState *env)
 | 
			
		||||
{
 | 
			
		||||
    if (arm_feature(env, ARM_FEATURE_EL3)) {
 | 
			
		||||
        return 3;
 | 
			
		||||
    }
 | 
			
		||||
    if (arm_feature(env, ARM_FEATURE_EL2)) {
 | 
			
		||||
        return 2;
 | 
			
		||||
    }
 | 
			
		||||
    return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Return the current Exception Level (as per ARMv8; note that this differs
 | 
			
		||||
 * from the ARMv7 Privilege Level).
 | 
			
		||||
 */
 | 
			
		||||
@ -1310,6 +1334,11 @@ typedef enum CPAccessResult {
 | 
			
		||||
    /* As CP_ACCESS_UNCATEGORIZED, but for traps directly to EL2 or EL3 */
 | 
			
		||||
    CP_ACCESS_TRAP_UNCATEGORIZED_EL2 = 5,
 | 
			
		||||
    CP_ACCESS_TRAP_UNCATEGORIZED_EL3 = 6,
 | 
			
		||||
    /* Access fails and results in an exception syndrome for an FP access,
 | 
			
		||||
     * trapped directly to EL2 or EL3
 | 
			
		||||
     */
 | 
			
		||||
    CP_ACCESS_TRAP_FP_EL2 = 7,
 | 
			
		||||
    CP_ACCESS_TRAP_FP_EL3 = 8,
 | 
			
		||||
} CPAccessResult;
 | 
			
		||||
 | 
			
		||||
/* Access functions for coprocessor registers. These cannot fail and
 | 
			
		||||
 | 
			
		||||
@ -135,6 +135,8 @@ static void aarch64_a57_initfn(Object *obj)
 | 
			
		||||
    cpu->id_isar5 = 0x00011121;
 | 
			
		||||
    cpu->id_aa64pfr0 = 0x00002222;
 | 
			
		||||
    cpu->id_aa64dfr0 = 0x10305106;
 | 
			
		||||
    cpu->pmceid0 = 0x00000000;
 | 
			
		||||
    cpu->pmceid1 = 0x00000000;
 | 
			
		||||
    cpu->id_aa64isar0 = 0x00011120;
 | 
			
		||||
    cpu->id_aa64mmfr0 = 0x00001124;
 | 
			
		||||
    cpu->dbgdidr = 0x3516d000;
 | 
			
		||||
 | 
			
		||||
@ -385,6 +385,60 @@ static CPAccessResult access_trap_aa32s_el1(CPUARMState *env,
 | 
			
		||||
    return CP_ACCESS_TRAP_UNCATEGORIZED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Check for traps to "powerdown debug" registers, which are controlled
 | 
			
		||||
 * by MDCR.TDOSA
 | 
			
		||||
 */
 | 
			
		||||
static CPAccessResult access_tdosa(CPUARMState *env, const ARMCPRegInfo *ri,
 | 
			
		||||
                                   bool isread)
 | 
			
		||||
{
 | 
			
		||||
    int el = arm_current_el(env);
 | 
			
		||||
 | 
			
		||||
    if (el < 2 && (env->cp15.mdcr_el2 & MDCR_TDOSA)
 | 
			
		||||
        && !arm_is_secure_below_el3(env)) {
 | 
			
		||||
        return CP_ACCESS_TRAP_EL2;
 | 
			
		||||
    }
 | 
			
		||||
    if (el < 3 && (env->cp15.mdcr_el3 & MDCR_TDOSA)) {
 | 
			
		||||
        return CP_ACCESS_TRAP_EL3;
 | 
			
		||||
    }
 | 
			
		||||
    return CP_ACCESS_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Check for traps to "debug ROM" registers, which are controlled
 | 
			
		||||
 * by MDCR_EL2.TDRA for EL2 but by the more general MDCR_EL3.TDA for EL3.
 | 
			
		||||
 */
 | 
			
		||||
static CPAccessResult access_tdra(CPUARMState *env, const ARMCPRegInfo *ri,
 | 
			
		||||
                                  bool isread)
 | 
			
		||||
{
 | 
			
		||||
    int el = arm_current_el(env);
 | 
			
		||||
 | 
			
		||||
    if (el < 2 && (env->cp15.mdcr_el2 & MDCR_TDRA)
 | 
			
		||||
        && !arm_is_secure_below_el3(env)) {
 | 
			
		||||
        return CP_ACCESS_TRAP_EL2;
 | 
			
		||||
    }
 | 
			
		||||
    if (el < 3 && (env->cp15.mdcr_el3 & MDCR_TDA)) {
 | 
			
		||||
        return CP_ACCESS_TRAP_EL3;
 | 
			
		||||
    }
 | 
			
		||||
    return CP_ACCESS_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Check for traps to general debug registers, which are controlled
 | 
			
		||||
 * by MDCR_EL2.TDA for EL2 and MDCR_EL3.TDA for EL3.
 | 
			
		||||
 */
 | 
			
		||||
static CPAccessResult access_tda(CPUARMState *env, const ARMCPRegInfo *ri,
 | 
			
		||||
                                  bool isread)
 | 
			
		||||
{
 | 
			
		||||
    int el = arm_current_el(env);
 | 
			
		||||
 | 
			
		||||
    if (el < 2 && (env->cp15.mdcr_el2 & MDCR_TDA)
 | 
			
		||||
        && !arm_is_secure_below_el3(env)) {
 | 
			
		||||
        return CP_ACCESS_TRAP_EL2;
 | 
			
		||||
    }
 | 
			
		||||
    if (el < 3 && (env->cp15.mdcr_el3 & MDCR_TDA)) {
 | 
			
		||||
        return CP_ACCESS_TRAP_EL3;
 | 
			
		||||
    }
 | 
			
		||||
    return CP_ACCESS_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dacr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
 | 
			
		||||
{
 | 
			
		||||
    ARMCPU *cpu = arm_env_get_cpu(env);
 | 
			
		||||
@ -1003,6 +1057,13 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
 | 
			
		||||
      .accessfn = pmreg_access,
 | 
			
		||||
      .writefn = pmovsr_write,
 | 
			
		||||
      .raw_writefn = raw_write },
 | 
			
		||||
    { .name = "PMOVSCLR_EL0", .state = ARM_CP_STATE_AA64,
 | 
			
		||||
      .opc0 = 3, .opc1 = 3, .crn = 9, .crm = 12, .opc2 = 3,
 | 
			
		||||
      .access = PL0_RW, .accessfn = pmreg_access,
 | 
			
		||||
      .type = ARM_CP_ALIAS,
 | 
			
		||||
      .fieldoffset = offsetof(CPUARMState, cp15.c9_pmovsr),
 | 
			
		||||
      .writefn = pmovsr_write,
 | 
			
		||||
      .raw_writefn = raw_write },
 | 
			
		||||
    /* Unimplemented so WI. */
 | 
			
		||||
    { .name = "PMSWINC", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 4,
 | 
			
		||||
      .access = PL0_W, .accessfn = pmreg_access, .type = ARM_CP_NOP },
 | 
			
		||||
@ -1044,6 +1105,12 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
 | 
			
		||||
      .fieldoffset = offsetof(CPUARMState, cp15.c9_pmuserenr),
 | 
			
		||||
      .resetvalue = 0,
 | 
			
		||||
      .writefn = pmuserenr_write, .raw_writefn = raw_write },
 | 
			
		||||
    { .name = "PMUSERENR_EL0", .state = ARM_CP_STATE_AA64,
 | 
			
		||||
      .opc0 = 3, .opc1 = 3, .crn = 9, .crm = 14, .opc2 = 0,
 | 
			
		||||
      .access = PL0_R | PL1_RW, .type = ARM_CP_ALIAS,
 | 
			
		||||
      .fieldoffset = offsetof(CPUARMState, cp15.c9_pmuserenr),
 | 
			
		||||
      .resetvalue = 0,
 | 
			
		||||
      .writefn = pmuserenr_write, .raw_writefn = raw_write },
 | 
			
		||||
    { .name = "PMINTENSET", .cp = 15, .crn = 9, .crm = 14, .opc1 = 0, .opc2 = 1,
 | 
			
		||||
      .access = PL1_RW,
 | 
			
		||||
      .fieldoffset = offsetof(CPUARMState, cp15.c9_pminten),
 | 
			
		||||
@ -1053,6 +1120,11 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
 | 
			
		||||
      .access = PL1_RW, .type = ARM_CP_ALIAS,
 | 
			
		||||
      .fieldoffset = offsetof(CPUARMState, cp15.c9_pminten),
 | 
			
		||||
      .writefn = pmintenclr_write, },
 | 
			
		||||
    { .name = "PMINTENCLR_EL1", .state = ARM_CP_STATE_AA64,
 | 
			
		||||
      .opc0 = 3, .opc1 = 0, .crn = 9, .crm = 14, .opc2 = 2,
 | 
			
		||||
      .access = PL1_RW, .type = ARM_CP_ALIAS,
 | 
			
		||||
      .fieldoffset = offsetof(CPUARMState, cp15.c9_pminten),
 | 
			
		||||
      .writefn = pmintenclr_write },
 | 
			
		||||
    { .name = "VBAR", .state = ARM_CP_STATE_BOTH,
 | 
			
		||||
      .opc0 = 3, .crn = 12, .crm = 0, .opc1 = 0, .opc2 = 0,
 | 
			
		||||
      .access = PL1_RW, .writefn = vbar_write,
 | 
			
		||||
@ -1218,10 +1290,33 @@ static const ARMCPRegInfo v6k_cp_reginfo[] = {
 | 
			
		||||
static CPAccessResult gt_cntfrq_access(CPUARMState *env, const ARMCPRegInfo *ri,
 | 
			
		||||
                                       bool isread)
 | 
			
		||||
{
 | 
			
		||||
    /* CNTFRQ: not visible from PL0 if both PL0PCTEN and PL0VCTEN are zero */
 | 
			
		||||
    if (arm_current_el(env) == 0 && !extract32(env->cp15.c14_cntkctl, 0, 2)) {
 | 
			
		||||
    /* CNTFRQ: not visible from PL0 if both PL0PCTEN and PL0VCTEN are zero.
 | 
			
		||||
     * Writable only at the highest implemented exception level.
 | 
			
		||||
     */
 | 
			
		||||
    int el = arm_current_el(env);
 | 
			
		||||
 | 
			
		||||
    switch (el) {
 | 
			
		||||
    case 0:
 | 
			
		||||
        if (!extract32(env->cp15.c14_cntkctl, 0, 2)) {
 | 
			
		||||
            return CP_ACCESS_TRAP;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    case 1:
 | 
			
		||||
        if (!isread && ri->state == ARM_CP_STATE_AA32 &&
 | 
			
		||||
            arm_is_secure_below_el3(env)) {
 | 
			
		||||
            /* Accesses from 32-bit Secure EL1 UNDEF (*not* trap to EL3!) */
 | 
			
		||||
            return CP_ACCESS_TRAP_UNCATEGORIZED;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    case 2:
 | 
			
		||||
    case 3:
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!isread && el < arm_highest_el(env)) {
 | 
			
		||||
        return CP_ACCESS_TRAP_UNCATEGORIZED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return CP_ACCESS_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -2934,10 +3029,10 @@ static CPAccessResult fpexc32_access(CPUARMState *env, const ARMCPRegInfo *ri,
 | 
			
		||||
                                     bool isread)
 | 
			
		||||
{
 | 
			
		||||
    if ((env->cp15.cptr_el[2] & CPTR_TFP) && arm_current_el(env) == 2) {
 | 
			
		||||
        return CP_ACCESS_TRAP_EL2;
 | 
			
		||||
        return CP_ACCESS_TRAP_FP_EL2;
 | 
			
		||||
    }
 | 
			
		||||
    if (env->cp15.cptr_el[3] & CPTR_TFP) {
 | 
			
		||||
        return CP_ACCESS_TRAP_EL3;
 | 
			
		||||
        return CP_ACCESS_TRAP_FP_EL3;
 | 
			
		||||
    }
 | 
			
		||||
    return CP_ACCESS_OK;
 | 
			
		||||
}
 | 
			
		||||
@ -3325,7 +3420,8 @@ static const ARMCPRegInfo el3_no_el2_cp_reginfo[] = {
 | 
			
		||||
      .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
 | 
			
		||||
    { .name = "MDCR_EL2", .state = ARM_CP_STATE_BOTH,
 | 
			
		||||
      .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 1,
 | 
			
		||||
      .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
 | 
			
		||||
      .access = PL2_RW, .accessfn = access_tda,
 | 
			
		||||
      .type = ARM_CP_CONST, .resetvalue = 0 },
 | 
			
		||||
    { .name = "HPFAR_EL2", .state = ARM_CP_STATE_BOTH,
 | 
			
		||||
      .opc0 = 3, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 4,
 | 
			
		||||
      .access = PL2_RW, .accessfn = access_el3_aa32ns_aa64any,
 | 
			
		||||
@ -3732,16 +3828,19 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
 | 
			
		||||
     * accessor.
 | 
			
		||||
     */
 | 
			
		||||
    { .name = "DBGDRAR", .cp = 14, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 0,
 | 
			
		||||
      .access = PL0_R, .type = ARM_CP_CONST, .resetvalue = 0 },
 | 
			
		||||
      .access = PL0_R, .accessfn = access_tdra,
 | 
			
		||||
      .type = ARM_CP_CONST, .resetvalue = 0 },
 | 
			
		||||
    { .name = "MDRAR_EL1", .state = ARM_CP_STATE_AA64,
 | 
			
		||||
      .opc0 = 2, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 0,
 | 
			
		||||
      .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 },
 | 
			
		||||
      .access = PL1_R, .accessfn = access_tdra,
 | 
			
		||||
      .type = ARM_CP_CONST, .resetvalue = 0 },
 | 
			
		||||
    { .name = "DBGDSAR", .cp = 14, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 0,
 | 
			
		||||
      .access = PL0_R, .type = ARM_CP_CONST, .resetvalue = 0 },
 | 
			
		||||
      .access = PL0_R, .accessfn = access_tdra,
 | 
			
		||||
      .type = ARM_CP_CONST, .resetvalue = 0 },
 | 
			
		||||
    /* Monitor debug system control register; the 32-bit alias is DBGDSCRext. */
 | 
			
		||||
    { .name = "MDSCR_EL1", .state = ARM_CP_STATE_BOTH,
 | 
			
		||||
      .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 2,
 | 
			
		||||
      .access = PL1_RW,
 | 
			
		||||
      .access = PL1_RW, .accessfn = access_tda,
 | 
			
		||||
      .fieldoffset = offsetof(CPUARMState, cp15.mdscr_el1),
 | 
			
		||||
      .resetvalue = 0 },
 | 
			
		||||
    /* MDCCSR_EL0, aka DBGDSCRint. This is a read-only mirror of MDSCR_EL1.
 | 
			
		||||
@ -3750,26 +3849,30 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
 | 
			
		||||
    { .name = "MDCCSR_EL0", .state = ARM_CP_STATE_BOTH,
 | 
			
		||||
      .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 0,
 | 
			
		||||
      .type = ARM_CP_ALIAS,
 | 
			
		||||
      .access = PL1_R,
 | 
			
		||||
      .access = PL1_R, .accessfn = access_tda,
 | 
			
		||||
      .fieldoffset = offsetof(CPUARMState, cp15.mdscr_el1), },
 | 
			
		||||
    { .name = "OSLAR_EL1", .state = ARM_CP_STATE_BOTH,
 | 
			
		||||
      .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 4,
 | 
			
		||||
      .access = PL1_W, .type = ARM_CP_NO_RAW,
 | 
			
		||||
      .accessfn = access_tdosa,
 | 
			
		||||
      .writefn = oslar_write },
 | 
			
		||||
    { .name = "OSLSR_EL1", .state = ARM_CP_STATE_BOTH,
 | 
			
		||||
      .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 4,
 | 
			
		||||
      .access = PL1_R, .resetvalue = 10,
 | 
			
		||||
      .accessfn = access_tdosa,
 | 
			
		||||
      .fieldoffset = offsetof(CPUARMState, cp15.oslsr_el1) },
 | 
			
		||||
    /* Dummy OSDLR_EL1: 32-bit Linux will read this */
 | 
			
		||||
    { .name = "OSDLR_EL1", .state = ARM_CP_STATE_BOTH,
 | 
			
		||||
      .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 1, .crm = 3, .opc2 = 4,
 | 
			
		||||
      .access = PL1_RW, .type = ARM_CP_NOP },
 | 
			
		||||
      .access = PL1_RW, .accessfn = access_tdosa,
 | 
			
		||||
      .type = ARM_CP_NOP },
 | 
			
		||||
    /* Dummy DBGVCR: Linux wants to clear this on startup, but we don't
 | 
			
		||||
     * implement vector catch debug events yet.
 | 
			
		||||
     */
 | 
			
		||||
    { .name = "DBGVCR",
 | 
			
		||||
      .cp = 14, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 0,
 | 
			
		||||
      .access = PL1_RW, .type = ARM_CP_NOP },
 | 
			
		||||
      .access = PL1_RW, .accessfn = access_tda,
 | 
			
		||||
      .type = ARM_CP_NOP },
 | 
			
		||||
    REGINFO_SENTINEL
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -4034,7 +4137,8 @@ static void define_debug_regs(ARMCPU *cpu)
 | 
			
		||||
    int wrps, brps, ctx_cmps;
 | 
			
		||||
    ARMCPRegInfo dbgdidr = {
 | 
			
		||||
        .name = "DBGDIDR", .cp = 14, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 0,
 | 
			
		||||
        .access = PL0_R, .type = ARM_CP_CONST, .resetvalue = cpu->dbgdidr,
 | 
			
		||||
        .access = PL0_R, .accessfn = access_tda,
 | 
			
		||||
        .type = ARM_CP_CONST, .resetvalue = cpu->dbgdidr,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /* Note that all these register fields hold "number of Xs minus 1". */
 | 
			
		||||
@ -4065,13 +4169,13 @@ static void define_debug_regs(ARMCPU *cpu)
 | 
			
		||||
        ARMCPRegInfo dbgregs[] = {
 | 
			
		||||
            { .name = "DBGBVR", .state = ARM_CP_STATE_BOTH,
 | 
			
		||||
              .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 4,
 | 
			
		||||
              .access = PL1_RW,
 | 
			
		||||
              .access = PL1_RW, .accessfn = access_tda,
 | 
			
		||||
              .fieldoffset = offsetof(CPUARMState, cp15.dbgbvr[i]),
 | 
			
		||||
              .writefn = dbgbvr_write, .raw_writefn = raw_write
 | 
			
		||||
            },
 | 
			
		||||
            { .name = "DBGBCR", .state = ARM_CP_STATE_BOTH,
 | 
			
		||||
              .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 5,
 | 
			
		||||
              .access = PL1_RW,
 | 
			
		||||
              .access = PL1_RW, .accessfn = access_tda,
 | 
			
		||||
              .fieldoffset = offsetof(CPUARMState, cp15.dbgbcr[i]),
 | 
			
		||||
              .writefn = dbgbcr_write, .raw_writefn = raw_write
 | 
			
		||||
            },
 | 
			
		||||
@ -4084,13 +4188,13 @@ static void define_debug_regs(ARMCPU *cpu)
 | 
			
		||||
        ARMCPRegInfo dbgregs[] = {
 | 
			
		||||
            { .name = "DBGWVR", .state = ARM_CP_STATE_BOTH,
 | 
			
		||||
              .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 6,
 | 
			
		||||
              .access = PL1_RW,
 | 
			
		||||
              .access = PL1_RW, .accessfn = access_tda,
 | 
			
		||||
              .fieldoffset = offsetof(CPUARMState, cp15.dbgwvr[i]),
 | 
			
		||||
              .writefn = dbgwvr_write, .raw_writefn = raw_write
 | 
			
		||||
            },
 | 
			
		||||
            { .name = "DBGWCR", .state = ARM_CP_STATE_BOTH,
 | 
			
		||||
              .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = i, .opc2 = 7,
 | 
			
		||||
              .access = PL1_RW,
 | 
			
		||||
              .access = PL1_RW, .accessfn = access_tda,
 | 
			
		||||
              .fieldoffset = offsetof(CPUARMState, cp15.dbgwcr[i]),
 | 
			
		||||
              .writefn = dbgwcr_write, .raw_writefn = raw_write
 | 
			
		||||
            },
 | 
			
		||||
@ -4294,6 +4398,22 @@ void register_cp_regs_for_features(ARMCPU *cpu)
 | 
			
		||||
              .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 2,
 | 
			
		||||
              .access = PL1_R, .type = ARM_CP_CONST,
 | 
			
		||||
              .resetvalue = cpu->mvfr2 },
 | 
			
		||||
            { .name = "PMCEID0", .state = ARM_CP_STATE_AA32,
 | 
			
		||||
              .cp = 15, .opc1 = 0, .crn = 9, .crm = 12, .opc2 = 6,
 | 
			
		||||
              .access = PL0_R, .accessfn = pmreg_access, .type = ARM_CP_CONST,
 | 
			
		||||
              .resetvalue = cpu->pmceid0 },
 | 
			
		||||
            { .name = "PMCEID0_EL0", .state = ARM_CP_STATE_AA64,
 | 
			
		||||
              .opc0 = 3, .opc1 = 3, .crn = 9, .crm = 12, .opc2 = 6,
 | 
			
		||||
              .access = PL0_R, .accessfn = pmreg_access, .type = ARM_CP_CONST,
 | 
			
		||||
              .resetvalue = cpu->pmceid0 },
 | 
			
		||||
            { .name = "PMCEID1", .state = ARM_CP_STATE_AA32,
 | 
			
		||||
              .cp = 15, .opc1 = 0, .crn = 9, .crm = 12, .opc2 = 7,
 | 
			
		||||
              .access = PL0_R, .accessfn = pmreg_access, .type = ARM_CP_CONST,
 | 
			
		||||
              .resetvalue = cpu->pmceid1 },
 | 
			
		||||
            { .name = "PMCEID1_EL0", .state = ARM_CP_STATE_AA64,
 | 
			
		||||
              .opc0 = 3, .opc1 = 3, .crn = 9, .crm = 12, .opc2 = 7,
 | 
			
		||||
              .access = PL0_R, .accessfn = pmreg_access, .type = ARM_CP_CONST,
 | 
			
		||||
              .resetvalue = cpu->pmceid1 },
 | 
			
		||||
            REGINFO_SENTINEL
 | 
			
		||||
        };
 | 
			
		||||
        /* RVBAR_EL1 is only implemented if EL1 is the highest EL */
 | 
			
		||||
@ -5279,21 +5399,6 @@ void switch_mode(CPUARMState *env, int mode)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HELPER(set_r13_banked)(CPUARMState *env, uint32_t mode, uint32_t val)
 | 
			
		||||
{
 | 
			
		||||
    ARMCPU *cpu = arm_env_get_cpu(env);
 | 
			
		||||
 | 
			
		||||
    cpu_abort(CPU(cpu), "banked r13 write\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t HELPER(get_r13_banked)(CPUARMState *env, uint32_t mode)
 | 
			
		||||
{
 | 
			
		||||
    ARMCPU *cpu = arm_env_get_cpu(env);
 | 
			
		||||
 | 
			
		||||
    cpu_abort(CPU(cpu), "banked r13 read\n");
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t arm_phys_excp_target_el(CPUState *cs, uint32_t excp_idx,
 | 
			
		||||
                                 uint32_t cur_el, bool secure)
 | 
			
		||||
{
 | 
			
		||||
@ -5307,31 +5412,6 @@ void aarch64_sync_64_to_32(CPUARMState *env)
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
/* Map CPU modes onto saved register banks.  */
 | 
			
		||||
int bank_number(int mode)
 | 
			
		||||
{
 | 
			
		||||
    switch (mode) {
 | 
			
		||||
    case ARM_CPU_MODE_USR:
 | 
			
		||||
    case ARM_CPU_MODE_SYS:
 | 
			
		||||
        return BANK_USRSYS;
 | 
			
		||||
    case ARM_CPU_MODE_SVC:
 | 
			
		||||
        return BANK_SVC;
 | 
			
		||||
    case ARM_CPU_MODE_ABT:
 | 
			
		||||
        return BANK_ABT;
 | 
			
		||||
    case ARM_CPU_MODE_UND:
 | 
			
		||||
        return BANK_UND;
 | 
			
		||||
    case ARM_CPU_MODE_IRQ:
 | 
			
		||||
        return BANK_IRQ;
 | 
			
		||||
    case ARM_CPU_MODE_FIQ:
 | 
			
		||||
        return BANK_FIQ;
 | 
			
		||||
    case ARM_CPU_MODE_HYP:
 | 
			
		||||
        return BANK_HYP;
 | 
			
		||||
    case ARM_CPU_MODE_MON:
 | 
			
		||||
        return BANK_MON;
 | 
			
		||||
    }
 | 
			
		||||
    g_assert_not_reached();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void switch_mode(CPUARMState *env, int mode)
 | 
			
		||||
{
 | 
			
		||||
    int old_mode;
 | 
			
		||||
@ -7676,24 +7756,6 @@ hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr,
 | 
			
		||||
    return phys_addr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HELPER(set_r13_banked)(CPUARMState *env, uint32_t mode, uint32_t val)
 | 
			
		||||
{
 | 
			
		||||
    if ((env->uncached_cpsr & CPSR_M) == mode) {
 | 
			
		||||
        env->regs[13] = val;
 | 
			
		||||
    } else {
 | 
			
		||||
        env->banked_r13[bank_number(mode)] = val;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t HELPER(get_r13_banked)(CPUARMState *env, uint32_t mode)
 | 
			
		||||
{
 | 
			
		||||
    if ((env->uncached_cpsr & CPSR_M) == mode) {
 | 
			
		||||
        return env->regs[13];
 | 
			
		||||
    } else {
 | 
			
		||||
        return env->banked_r13[bank_number(mode)];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
 | 
			
		||||
{
 | 
			
		||||
    ARMCPU *cpu = arm_env_get_cpu(env);
 | 
			
		||||
 | 
			
		||||
@ -109,7 +109,31 @@ static inline unsigned int aarch64_banked_spsr_index(unsigned int el)
 | 
			
		||||
    return map[el];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int bank_number(int mode);
 | 
			
		||||
/* Map CPU modes onto saved register banks.  */
 | 
			
		||||
static inline int bank_number(int mode)
 | 
			
		||||
{
 | 
			
		||||
    switch (mode) {
 | 
			
		||||
    case ARM_CPU_MODE_USR:
 | 
			
		||||
    case ARM_CPU_MODE_SYS:
 | 
			
		||||
        return BANK_USRSYS;
 | 
			
		||||
    case ARM_CPU_MODE_SVC:
 | 
			
		||||
        return BANK_SVC;
 | 
			
		||||
    case ARM_CPU_MODE_ABT:
 | 
			
		||||
        return BANK_ABT;
 | 
			
		||||
    case ARM_CPU_MODE_UND:
 | 
			
		||||
        return BANK_UND;
 | 
			
		||||
    case ARM_CPU_MODE_IRQ:
 | 
			
		||||
        return BANK_IRQ;
 | 
			
		||||
    case ARM_CPU_MODE_FIQ:
 | 
			
		||||
        return BANK_FIQ;
 | 
			
		||||
    case ARM_CPU_MODE_HYP:
 | 
			
		||||
        return BANK_HYP;
 | 
			
		||||
    case ARM_CPU_MODE_MON:
 | 
			
		||||
        return BANK_MON;
 | 
			
		||||
    }
 | 
			
		||||
    g_assert_not_reached();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void switch_mode(CPUARMState *, int);
 | 
			
		||||
void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu);
 | 
			
		||||
void arm_translate_init(void);
 | 
			
		||||
 | 
			
		||||
@ -457,6 +457,32 @@ void HELPER(set_user_reg)(CPUARMState *env, uint32_t regno, uint32_t val)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HELPER(set_r13_banked)(CPUARMState *env, uint32_t mode, uint32_t val)
 | 
			
		||||
{
 | 
			
		||||
    if ((env->uncached_cpsr & CPSR_M) == mode) {
 | 
			
		||||
        env->regs[13] = val;
 | 
			
		||||
    } else {
 | 
			
		||||
        env->banked_r13[bank_number(mode)] = val;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t HELPER(get_r13_banked)(CPUARMState *env, uint32_t mode)
 | 
			
		||||
{
 | 
			
		||||
    if ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_SYS) {
 | 
			
		||||
        /* SRS instruction is UNPREDICTABLE from System mode; we UNDEF.
 | 
			
		||||
         * Other UNPREDICTABLE and UNDEF cases were caught at translate time.
 | 
			
		||||
         */
 | 
			
		||||
        raise_exception(env, EXCP_UDEF, syn_uncategorized(),
 | 
			
		||||
                        exception_target_el(env));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((env->uncached_cpsr & CPSR_M) == mode) {
 | 
			
		||||
        return env->regs[13];
 | 
			
		||||
    } else {
 | 
			
		||||
        return env->banked_r13[bank_number(mode)];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome,
 | 
			
		||||
                                 uint32_t isread)
 | 
			
		||||
{
 | 
			
		||||
@ -500,6 +526,19 @@ void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome,
 | 
			
		||||
        target_el = 3;
 | 
			
		||||
        syndrome = syn_uncategorized();
 | 
			
		||||
        break;
 | 
			
		||||
    case CP_ACCESS_TRAP_FP_EL2:
 | 
			
		||||
        target_el = 2;
 | 
			
		||||
        /* Since we are an implementation that takes exceptions on a trapped
 | 
			
		||||
         * conditional insn only if the insn has passed its condition code
 | 
			
		||||
         * check, we take the IMPDEF choice to always report CV=1 COND=0xe
 | 
			
		||||
         * (which is also the required value for AArch64 traps).
 | 
			
		||||
         */
 | 
			
		||||
        syndrome = syn_fp_access_trap(1, 0xe, false);
 | 
			
		||||
        break;
 | 
			
		||||
    case CP_ACCESS_TRAP_FP_EL3:
 | 
			
		||||
        target_el = 3;
 | 
			
		||||
        syndrome = syn_fp_access_trap(1, 0xe, false);
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        g_assert_not_reached();
 | 
			
		||||
    }
 | 
			
		||||
@ -614,12 +653,14 @@ void HELPER(pre_smc)(CPUARMState *env, uint32_t syndrome)
 | 
			
		||||
    int cur_el = arm_current_el(env);
 | 
			
		||||
    bool secure = arm_is_secure(env);
 | 
			
		||||
    bool smd = env->cp15.scr_el3 & SCR_SMD;
 | 
			
		||||
    /* On ARMv8 AArch32, SMD only applies to NS state.
 | 
			
		||||
     * On ARMv7 SMD only applies to NS state and only if EL2 is available.
 | 
			
		||||
     * For ARMv7 non EL2, we force SMD to zero so we don't need to re-check
 | 
			
		||||
     * the EL2 condition here.
 | 
			
		||||
    /* On ARMv8 with EL3 AArch64, SMD applies to both S and NS state.
 | 
			
		||||
     * On ARMv8 with EL3 AArch32, or ARMv7 with the Virtualization
 | 
			
		||||
     *  extensions, SMD only applies to NS state.
 | 
			
		||||
     * On ARMv7 without the Virtualization extensions, the SMD bit
 | 
			
		||||
     * doesn't exist, but we forbid the guest to set it to 1 in scr_write(),
 | 
			
		||||
     * so we need not special case this here.
 | 
			
		||||
     */
 | 
			
		||||
    bool undef = is_a64(env) ? smd : (!secure && smd);
 | 
			
		||||
    bool undef = arm_feature(env, ARM_FEATURE_AARCH64) ? smd : smd && !secure;
 | 
			
		||||
 | 
			
		||||
    if (arm_is_psci_call(cpu, EXCP_SMC)) {
 | 
			
		||||
        /* If PSCI is enabled and this looks like a valid PSCI call then
 | 
			
		||||
 | 
			
		||||
@ -7578,8 +7578,67 @@ static void gen_srs(DisasContext *s,
 | 
			
		||||
                    uint32_t mode, uint32_t amode, bool writeback)
 | 
			
		||||
{
 | 
			
		||||
    int32_t offset;
 | 
			
		||||
    TCGv_i32 addr = tcg_temp_new_i32();
 | 
			
		||||
    TCGv_i32 tmp = tcg_const_i32(mode);
 | 
			
		||||
    TCGv_i32 addr, tmp;
 | 
			
		||||
    bool undef = false;
 | 
			
		||||
 | 
			
		||||
    /* SRS is:
 | 
			
		||||
     * - trapped to EL3 if EL3 is AArch64 and we are at Secure EL1
 | 
			
		||||
     * - UNDEFINED in Hyp mode
 | 
			
		||||
     * - UNPREDICTABLE in User or System mode
 | 
			
		||||
     * - UNPREDICTABLE if the specified mode is:
 | 
			
		||||
     * -- not implemented
 | 
			
		||||
     * -- not a valid mode number
 | 
			
		||||
     * -- a mode that's at a higher exception level
 | 
			
		||||
     * -- Monitor, if we are Non-secure
 | 
			
		||||
     * For the UNPREDICTABLE cases we choose to UNDEF.
 | 
			
		||||
     */
 | 
			
		||||
    if (s->current_el == 1 && !s->ns) {
 | 
			
		||||
        gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized(), 3);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (s->current_el == 0 || s->current_el == 2) {
 | 
			
		||||
        undef = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    switch (mode) {
 | 
			
		||||
    case ARM_CPU_MODE_USR:
 | 
			
		||||
    case ARM_CPU_MODE_FIQ:
 | 
			
		||||
    case ARM_CPU_MODE_IRQ:
 | 
			
		||||
    case ARM_CPU_MODE_SVC:
 | 
			
		||||
    case ARM_CPU_MODE_ABT:
 | 
			
		||||
    case ARM_CPU_MODE_UND:
 | 
			
		||||
    case ARM_CPU_MODE_SYS:
 | 
			
		||||
        break;
 | 
			
		||||
    case ARM_CPU_MODE_HYP:
 | 
			
		||||
        if (s->current_el == 1 || !arm_dc_feature(s, ARM_FEATURE_EL2)) {
 | 
			
		||||
            undef = true;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    case ARM_CPU_MODE_MON:
 | 
			
		||||
        /* No need to check specifically for "are we non-secure" because
 | 
			
		||||
         * we've already made EL0 UNDEF and handled the trap for S-EL1;
 | 
			
		||||
         * so if this isn't EL3 then we must be non-secure.
 | 
			
		||||
         */
 | 
			
		||||
        if (s->current_el != 3) {
 | 
			
		||||
            undef = true;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        undef = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (undef) {
 | 
			
		||||
        gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized(),
 | 
			
		||||
                           default_exception_el(s));
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    addr = tcg_temp_new_i32();
 | 
			
		||||
    tmp = tcg_const_i32(mode);
 | 
			
		||||
    /* get_r13_banked() will raise an exception if called from System mode */
 | 
			
		||||
    gen_set_condexec(s);
 | 
			
		||||
    gen_set_pc_im(s, s->pc - 4);
 | 
			
		||||
    gen_helper_get_r13_banked(addr, cpu_env, tmp);
 | 
			
		||||
    tcg_temp_free_i32(tmp);
 | 
			
		||||
    switch (amode) {
 | 
			
		||||
@ -7629,6 +7688,7 @@ static void gen_srs(DisasContext *s,
 | 
			
		||||
        tcg_temp_free_i32(tmp);
 | 
			
		||||
    }
 | 
			
		||||
    tcg_temp_free_i32(addr);
 | 
			
		||||
    s->is_jmp = DISAS_UPDATE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void disas_arm_insn(DisasContext *s, unsigned int insn)
 | 
			
		||||
@ -7739,9 +7799,6 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
 | 
			
		||||
            }
 | 
			
		||||
        } else if ((insn & 0x0e5fffe0) == 0x084d0500) {
 | 
			
		||||
            /* srs */
 | 
			
		||||
            if (IS_USER(s)) {
 | 
			
		||||
                goto illegal_op;
 | 
			
		||||
            }
 | 
			
		||||
            ARCH(6);
 | 
			
		||||
            gen_srs(s, (insn & 0x1f), (insn >> 23) & 3, insn & (1 << 21));
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user