summaryrefslogtreecommitdiffstats
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/9pfs/virtio-9p-coth.c4
-rw-r--r--hw/9pfs/virtio-9p-debug.c2
-rw-r--r--hw/fdc.c4
-rw-r--r--hw/g364fb.c16
-rw-r--r--hw/hid.c2
-rw-r--r--hw/ide/ahci.c2
-rw-r--r--hw/ide/ahci.h1
-rw-r--r--hw/ide/atapi.c58
-rw-r--r--hw/ide/cmd646.c1
-rw-r--r--hw/ide/core.c160
-rw-r--r--hw/ide/ich.c1
-rw-r--r--hw/ide/internal.h3
-rw-r--r--hw/ide/isa.c1
-rw-r--r--hw/ide/macio.c1
-rw-r--r--hw/ide/microdrive.c1
-rw-r--r--hw/ide/mmio.c1
-rw-r--r--hw/ide/pci.c1
-rw-r--r--hw/ide/via.c1
-rw-r--r--hw/lsi53c895a.c6
-rw-r--r--hw/mips.h3
-rw-r--r--hw/mips_mipssim.c18
-rw-r--r--hw/mipsnet.c106
-rw-r--r--hw/pci.c14
-rw-r--r--hw/pci.h2
-rw-r--r--hw/scsi-bus.c14
-rw-r--r--hw/scsi-disk.c69
-rw-r--r--hw/scsi-generic.c1
-rw-r--r--hw/scsi.h5
-rw-r--r--hw/sd.c2
-rw-r--r--hw/virtio-balloon.c2
-rw-r--r--hw/virtio-blk.c5
-rw-r--r--hw/virtio.h2
-rw-r--r--hw/xen_backend.c40
-rw-r--r--hw/xen_backend.h3
-rw-r--r--hw/xen_console.c4
-rw-r--r--hw/xen_disk.c2
-rw-r--r--hw/xen_nic.c2
-rw-r--r--hw/xenfb.c29
-rw-r--r--hw/xtensa_dc232b.c116
-rw-r--r--hw/xtensa_pic.c134
-rw-r--r--hw/xtensa_sample.c107
41 files changed, 743 insertions, 203 deletions
diff --git a/hw/9pfs/virtio-9p-coth.c b/hw/9pfs/virtio-9p-coth.c
index ae05658632..25556cc6a7 100644
--- a/hw/9pfs/virtio-9p-coth.c
+++ b/hw/9pfs/virtio-9p-coth.c
@@ -67,10 +67,6 @@ int v9fs_init_worker_threads(void)
/* Leave signal handling to the iothread. */
pthread_sigmask(SIG_SETMASK, &set, &oldset);
- /* init thread system if not already initialized */
- if (!g_thread_get_initialized()) {
- g_thread_init(NULL);
- }
if (qemu_pipe(notifier_fds) == -1) {
ret = -1;
goto err_out;
diff --git a/hw/9pfs/virtio-9p-debug.c b/hw/9pfs/virtio-9p-debug.c
index 4636ad51f0..96925f04a4 100644
--- a/hw/9pfs/virtio-9p-debug.c
+++ b/hw/9pfs/virtio-9p-debug.c
@@ -295,7 +295,7 @@ static void pprint_data(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
if (rx) {
count = pdu->elem.in_num;
- } else
+ } else {
count = pdu->elem.out_num;
}
diff --git a/hw/fdc.c b/hw/fdc.c
index 1d44bbd1e3..433af73ad7 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -36,7 +36,6 @@
#include "qdev-addr.h"
#include "blockdev.h"
#include "sysemu.h"
-#include "block_int.h"
/********************************************************/
/* debug Floppy devices */
@@ -1778,7 +1777,7 @@ static void fdctrl_result_timer(void *opaque)
fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
}
-static void fdctrl_change_cb(void *opaque)
+static void fdctrl_change_cb(void *opaque, bool load)
{
FDrive *drive = opaque;
@@ -1813,7 +1812,6 @@ static int fdctrl_connect_drives(FDCtrl *fdctrl)
fd_revalidate(drive);
if (drive->bs) {
drive->media_changed = 1;
- bdrv_set_removable(drive->bs, 1);
bdrv_set_dev_ops(drive->bs, &fdctrl_block_ops, drive);
}
}
diff --git a/hw/g364fb.c b/hw/g364fb.c
index 5e7bcfa278..b43341f8d7 100644
--- a/hw/g364fb.c
+++ b/hw/g364fb.c
@@ -58,6 +58,8 @@ typedef struct G364State {
#define CTLA_FORCE_BLANK 0x00000400
#define CTLA_NO_CURSOR 0x00800000
+#define G364_PAGE_SIZE 4096
+
static inline int check_dirty(G364State *s, ram_addr_t page)
{
return memory_region_get_dirty(&s->mem_vram, page, DIRTY_MEMORY_VGA);
@@ -68,7 +70,7 @@ static inline void reset_dirty(G364State *s,
{
memory_region_reset_dirty(&s->mem_vram,
page_min,
- page_max + TARGET_PAGE_SIZE - page_min - 1,
+ page_max + G364_PAGE_SIZE - page_min - 1,
DIRTY_MEMORY_VGA);
}
@@ -136,7 +138,7 @@ static void g364fb_draw_graphic8(G364State *s)
page_max = page;
if (x < xmin)
xmin = x;
- for (i = 0; i < TARGET_PAGE_SIZE; i++) {
+ for (i = 0; i < G364_PAGE_SIZE; i++) {
uint8_t index;
unsigned int color;
if (unlikely((y >= ycursor && y < ycursor + 64) &&
@@ -200,15 +202,15 @@ static void g364fb_draw_graphic8(G364State *s)
ymin = s->height;
ymax = 0;
}
- x += TARGET_PAGE_SIZE;
+ x += G364_PAGE_SIZE;
dy = x / s->width;
x = x % s->width;
y += dy;
- vram += TARGET_PAGE_SIZE;
+ vram += G364_PAGE_SIZE;
data_display += dy * ds_get_linesize(s->ds);
dd = data_display + x * w;
}
- page += TARGET_PAGE_SIZE;
+ page += G364_PAGE_SIZE;
}
done:
@@ -267,7 +269,7 @@ static inline void g364fb_invalidate_display(void *opaque)
int i;
s->blanked = 0;
- for (i = 0; i < s->vram_size; i += TARGET_PAGE_SIZE) {
+ for (i = 0; i < s->vram_size; i += G364_PAGE_SIZE) {
memory_region_set_dirty(&s->mem_vram, i);
}
}
@@ -387,7 +389,7 @@ static void g364_invalidate_cursor_position(G364State *s)
start = ymin * ds_get_linesize(s->ds);
end = (ymax + 1) * ds_get_linesize(s->ds);
- for (i = start; i < end; i += TARGET_PAGE_SIZE) {
+ for (i = start; i < end; i += G364_PAGE_SIZE) {
memory_region_set_dirty(&s->mem_vram, i);
}
}
diff --git a/hw/hid.c b/hw/hid.c
index ec066cf2d3..03761ab8b8 100644
--- a/hw/hid.c
+++ b/hw/hid.c
@@ -96,7 +96,7 @@ static void hid_pointer_event_combine(HIDPointerEvent *e, int xyrel,
/* Windows drivers do not like the 0/0 position and ignore such
* events. */
if (!(x1 | y1)) {
- x1 = 1;
+ e->xdx = 1;
}
}
e->dz += z1;
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index f4fa1545bd..a8659cf8b9 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -754,7 +754,6 @@ static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis,
case READ_FPDMA_QUEUED:
DPRINTF(port, "NCQ reading %d sectors from LBA %ld, tag %d\n",
ncq_tfs->sector_count-1, ncq_tfs->lba, ncq_tfs->tag);
- ncq_tfs->is_read = 1;
DPRINTF(port, "tag %d aio read %ld\n", ncq_tfs->tag, ncq_tfs->lba);
@@ -768,7 +767,6 @@ static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis,
case WRITE_FPDMA_QUEUED:
DPRINTF(port, "NCQ writing %d sectors to LBA %ld, tag %d\n",
ncq_tfs->sector_count-1, ncq_tfs->lba, ncq_tfs->tag);
- ncq_tfs->is_read = 0;
DPRINTF(port, "tag %d aio write %ld\n", ncq_tfs->tag, ncq_tfs->lba);
diff --git a/hw/ide/ahci.h b/hw/ide/ahci.h
index 3c29d93b47..5de986c90f 100644
--- a/hw/ide/ahci.h
+++ b/hw/ide/ahci.h
@@ -259,7 +259,6 @@ typedef struct NCQTransferState {
BlockDriverAIOCB *aiocb;
QEMUSGList sglist;
BlockAcctCookie acct;
- int is_read;
uint16_t sector_count;
uint64_t lba;
uint8_t tag;
diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c
index f38d2896ae..3f909c3a99 100644
--- a/hw/ide/atapi.c
+++ b/hw/ide/atapi.c
@@ -73,7 +73,7 @@ static void lba_to_msf(uint8_t *buf, int lba)
static inline int media_present(IDEState *s)
{
- return (s->nb_sectors > 0);
+ return !s->tray_open && s->nb_sectors > 0;
}
/* XXX: DVDs that could fit on a CD will be reported as a CD */
@@ -521,7 +521,7 @@ static unsigned int event_status_media(IDEState *s,
uint8_t event_code, media_status;
media_status = 0;
- if (s->bs->tray_open) {
+ if (s->tray_open) {
media_status = MS_TRAY_OPEN;
} else if (bdrv_is_inserted(s->bs)) {
media_status = MS_MEDIA_PRESENT;
@@ -788,8 +788,9 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
buf[12] = 0x71;
buf[13] = 3 << 5;
buf[14] = (1 << 0) | (1 << 3) | (1 << 5);
- if (bdrv_is_locked(s->bs))
+ if (s->tray_locked) {
buf[6] |= 1 << 1;
+ }
buf[15] = 0x00;
cpu_to_ube16(&buf[16], 706);
buf[18] = 0;
@@ -831,7 +832,8 @@ static void cmd_test_unit_ready(IDEState *s, uint8_t *buf)
static void cmd_prevent_allow_medium_removal(IDEState *s, uint8_t* buf)
{
- bdrv_set_locked(s->bs, buf[4] & 1);
+ s->tray_locked = buf[4] & 1;
+ bdrv_lock_medium(s->bs, buf[4] & 1);
ide_atapi_cmd_ok(s);
}
@@ -903,29 +905,22 @@ static void cmd_seek(IDEState *s, uint8_t* buf)
static void cmd_start_stop_unit(IDEState *s, uint8_t* buf)
{
- int start, eject, sense, err = 0;
- start = buf[4] & 1;
- eject = (buf[4] >> 1) & 1;
-
- if (eject) {
- err = bdrv_eject(s->bs, !start);
- }
-
- switch (err) {
- case 0:
- ide_atapi_cmd_ok(s);
- break;
- case -EBUSY:
- sense = SENSE_NOT_READY;
- if (bdrv_is_inserted(s->bs)) {
- sense = SENSE_ILLEGAL_REQUEST;
+ int sense;
+ bool start = buf[4] & 1;
+ bool loej = buf[4] & 2; /* load on start, eject on !start */
+
+ if (loej) {
+ if (!start && !s->tray_open && s->tray_locked) {
+ sense = bdrv_is_inserted(s->bs)
+ ? SENSE_NOT_READY : SENSE_ILLEGAL_REQUEST;
+ ide_atapi_cmd_error(s, sense, ASC_MEDIA_REMOVAL_PREVENTED);
+ return;
}
- ide_atapi_cmd_error(s, sense, ASC_MEDIA_REMOVAL_PREVENTED);
- break;
- default:
- ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
- break;
+ bdrv_eject(s->bs, !start);
+ s->tray_open = !start;
}
+
+ ide_atapi_cmd_ok(s);
}
static void cmd_mechanism_status(IDEState *s, uint8_t* buf)
@@ -1073,20 +1068,21 @@ static const struct {
[ 0x03 ] = { cmd_request_sense, ALLOW_UA },
[ 0x12 ] = { cmd_inquiry, ALLOW_UA },
[ 0x1a ] = { cmd_mode_sense, /* (6) */ 0 },
- [ 0x1b ] = { cmd_start_stop_unit, 0 },
+ [ 0x1b ] = { cmd_start_stop_unit, 0 }, /* [1] */
[ 0x1e ] = { cmd_prevent_allow_medium_removal, 0 },
[ 0x25 ] = { cmd_read_cdvd_capacity, CHECK_READY },
- [ 0x28 ] = { cmd_read, /* (10) */ 0 },
+ [ 0x28 ] = { cmd_read, /* (10) */ CHECK_READY },
[ 0x2b ] = { cmd_seek, CHECK_READY },
[ 0x43 ] = { cmd_read_toc_pma_atip, CHECK_READY },
[ 0x46 ] = { cmd_get_configuration, ALLOW_UA },
[ 0x4a ] = { cmd_get_event_status_notification, ALLOW_UA },
[ 0x5a ] = { cmd_mode_sense, /* (10) */ 0 },
- [ 0xa8 ] = { cmd_read, /* (12) */ 0 },
- [ 0xad ] = { cmd_read_dvd_structure, 0 },
+ [ 0xa8 ] = { cmd_read, /* (12) */ CHECK_READY },
+ [ 0xad ] = { cmd_read_dvd_structure, CHECK_READY },
[ 0xbb ] = { cmd_set_speed, 0 },
[ 0xbd ] = { cmd_mechanism_status, 0 },
- [ 0xbe ] = { cmd_read_cd, 0 },
+ [ 0xbe ] = { cmd_read_cd, CHECK_READY },
+ /* [1] handler detects and reports not ready condition itself */
};
void ide_atapi_cmd(IDEState *s)
@@ -1122,7 +1118,7 @@ void ide_atapi_cmd(IDEState *s)
* GET_EVENT_STATUS_NOTIFICATION to detect such tray open/close
* states rely on this behavior.
*/
- if (bdrv_is_inserted(s->bs) && s->cdrom_changed) {
+ if (!s->tray_open && bdrv_is_inserted(s->bs) && s->cdrom_changed) {
ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
s->cdrom_changed = 0;
diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c
index 4d91e2c642..5fe98b1bb3 100644
--- a/hw/ide/cmd646.c
+++ b/hw/ide/cmd646.c
@@ -27,7 +27,6 @@
#include <hw/pci.h>
#include <hw/isa.h>
#include "block.h"
-#include "block_int.h"
#include "sysemu.h"
#include "dma.h"
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 1806e008bc..9297b9e657 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -30,6 +30,7 @@
#include "sysemu.h"
#include "dma.h"
#include "blockdev.h"
+#include "block_int.h"
#include <hw/ide/internal.h>
@@ -783,11 +784,12 @@ static void ide_cfata_metadata_write(IDEState *s)
}
/* called when the inserted state of the media has changed */
-static void ide_cd_change_cb(void *opaque)
+static void ide_cd_change_cb(void *opaque, bool load)
{
IDEState *s = opaque;
uint64_t nb_sectors;
+ s->tray_open = !load;
bdrv_get_geometry(s->bs, &nb_sectors);
s->nb_sectors = nb_sectors;
@@ -901,6 +903,78 @@ void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
}
}
+#define HD_OK (1u << IDE_HD)
+#define CD_OK (1u << IDE_CD)
+#define CFA_OK (1u << IDE_CFATA)
+#define HD_CFA_OK (HD_OK | CFA_OK)
+#define ALL_OK (HD_OK | CD_OK | CFA_OK)
+
+/* See ACS-2 T13/2015-D Table B.2 Command codes */
+static const uint8_t ide_cmd_table[0x100] = {
+ /* NOP not implemented, mandatory for CD */
+ [CFA_REQ_EXT_ERROR_CODE] = CFA_OK,
+ [WIN_DSM] = ALL_OK,
+ [WIN_DEVICE_RESET] = CD_OK,
+ [WIN_RECAL] = HD_CFA_OK,
+ [WIN_READ] = ALL_OK,
+ [WIN_READ_ONCE] = ALL_OK,
+ [WIN_READ_EXT] = HD_CFA_OK,
+ [WIN_READDMA_EXT] = HD_CFA_OK,
+ [WIN_READ_NATIVE_MAX_EXT] = HD_CFA_OK,
+ [WIN_MULTREAD_EXT] = HD_CFA_OK,
+ [WIN_WRITE] = HD_CFA_OK,
+ [WIN_WRITE_ONCE] = HD_CFA_OK,
+ [WIN_WRITE_EXT] = HD_CFA_OK,
+ [WIN_WRITEDMA_EXT] = HD_CFA_OK,
+ [CFA_WRITE_SECT_WO_ERASE] = CFA_OK,
+ [WIN_MULTWRITE_EXT] = HD_CFA_OK,
+ [WIN_WRITE_VERIFY] = HD_CFA_OK,
+ [WIN_VERIFY] = HD_CFA_OK,
+ [WIN_VERIFY_ONCE] = HD_CFA_OK,
+ [WIN_VERIFY_EXT] = HD_CFA_OK,
+ [WIN_SEEK] = HD_CFA_OK,
+ [CFA_TRANSLATE_SECTOR] = CFA_OK,
+ [WIN_DIAGNOSE] = ALL_OK,
+ [WIN_SPECIFY] = HD_CFA_OK,
+ [WIN_STANDBYNOW2] = ALL_OK,
+ [WIN_IDLEIMMEDIATE2] = ALL_OK,
+ [WIN_STANDBY2] = ALL_OK,
+ [WIN_SETIDLE2] = ALL_OK,
+ [WIN_CHECKPOWERMODE2] = ALL_OK,
+ [WIN_SLEEPNOW2] = ALL_OK,
+ [WIN_PACKETCMD] = CD_OK,
+ [WIN_PIDENTIFY] = CD_OK,
+ [WIN_SMART] = HD_CFA_OK,
+ [CFA_ACCESS_METADATA_STORAGE] = CFA_OK,
+ [CFA_ERASE_SECTORS] = CFA_OK,
+ [WIN_MULTREAD] = HD_CFA_OK,
+ [WIN_MULTWRITE] = HD_CFA_OK,
+ [WIN_SETMULT] = HD_CFA_OK,
+ [WIN_READDMA] = HD_CFA_OK,
+ [WIN_READDMA_ONCE] = HD_CFA_OK,
+ [WIN_WRITEDMA] = HD_CFA_OK,
+ [WIN_WRITEDMA_ONCE] = HD_CFA_OK,
+ [CFA_WRITE_MULTI_WO_ERASE] = CFA_OK,
+ [WIN_STANDBYNOW1] = ALL_OK,
+ [WIN_IDLEIMMEDIATE] = ALL_OK,
+ [WIN_STANDBY] = ALL_OK,
+ [WIN_SETIDLE1] = ALL_OK,
+ [WIN_CHECKPOWERMODE1] = ALL_OK,
+ [WIN_SLEEPNOW1] = ALL_OK,
+ [WIN_FLUSH_CACHE] = ALL_OK,
+ [WIN_FLUSH_CACHE_EXT] = HD_CFA_OK,
+ [WIN_IDENTIFY] = ALL_OK,
+ [WIN_SETFEATURES] = ALL_OK,
+ [IBM_SENSE_CONDITION] = CFA_OK,
+ [CFA_WEAR_LEVEL] = CFA_OK,
+ [WIN_READ_NATIVE_MAX] = ALL_OK,
+};
+
+static bool ide_cmd_permitted(IDEState *s, uint32_t cmd)
+{
+ return cmd < ARRAY_SIZE(ide_cmd_table)
+ && (ide_cmd_table[cmd] & (1u << s->drive_kind));
+}
void ide_exec_cmd(IDEBus *bus, uint32_t val)
{
@@ -920,6 +994,10 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
if ((s->status & (BUSY_STAT|DRQ_STAT)) && val != WIN_DEVICE_RESET)
return;
+ if (!ide_cmd_permitted(s, val)) {
+ goto abort_cmd;
+ }
+
switch(val) {
case WIN_DSM:
switch (s->feature) {
@@ -983,8 +1061,10 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
lba48 = 1;
case WIN_READ:
case WIN_READ_ONCE:
- if (!s->bs)
+ if (s->drive_kind == IDE_CD) {
+ ide_set_signature(s); /* odd, but ATA4 8.27.5.2 requires it */
goto abort_cmd;
+ }
ide_cmd_lba48_transform(s, lba48);
s->req_nb_sectors = 1;
ide_sector_read(s);
@@ -1138,21 +1218,15 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
ide_set_irq(s->bus);
break;
case WIN_SEEK:
- if(s->drive_kind == IDE_CD)
- goto abort_cmd;
/* XXX: Check that seek is within bounds */
s->status = READY_STAT | SEEK_STAT;
ide_set_irq(s->bus);
break;
/* ATAPI commands */
case WIN_PIDENTIFY:
- if (s->drive_kind == IDE_CD) {
- ide_atapi_identify(s);
- s->status = READY_STAT | SEEK_STAT;
- ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop);
- } else {
- ide_abort_command(s);
- }
+ ide_atapi_identify(s);
+ s->status = READY_STAT | SEEK_STAT;
+ ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop);
ide_set_irq(s->bus);
break;
case WIN_DIAGNOSE:
@@ -1169,15 +1243,11 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
ide_set_irq(s->bus);
break;
case WIN_DEVICE_RESET:
- if (s->drive_kind != IDE_CD)
- goto abort_cmd;
ide_set_signature(s);
s->status = 0x00; /* NOTE: READY is _not_ set */
s->error = 0x01;
break;
case WIN_PACKETCMD:
- if (s->drive_kind != IDE_CD)
- goto abort_cmd;
/* overlapping commands not supported */
if (s->feature & 0x02)
goto abort_cmd;
@@ -1189,16 +1259,12 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
break;
/* CF-ATA commands */
case CFA_REQ_EXT_ERROR_CODE:
- if (s->drive_kind != IDE_CFATA)
- goto abort_cmd;
s->error = 0x09; /* miscellaneous error */
s->status = READY_STAT | SEEK_STAT;
ide_set_irq(s->bus);
break;
case CFA_ERASE_SECTORS:
case CFA_WEAR_LEVEL:
- if (s->drive_kind != IDE_CFATA)
- goto abort_cmd;
if (val == CFA_WEAR_LEVEL)
s->nsector = 0;
if (val == CFA_ERASE_SECTORS)
@@ -1208,8 +1274,6 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
ide_set_irq(s->bus);
break;
case CFA_TRANSLATE_SECTOR:
- if (s->drive_kind != IDE_CFATA)
- goto abort_cmd;
s->error = 0x00;
s->status = READY_STAT | SEEK_STAT;
memset(s->io_buffer, 0, 0x200);
@@ -1228,8 +1292,6 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
ide_set_irq(s->bus);
break;
case CFA_ACCESS_METADATA_STORAGE:
- if (s->drive_kind != IDE_CFATA)
- goto abort_cmd;
switch (s->feature) {
case 0x02: /* Inquiry Metadata Storage */
ide_cfata_metadata_inquiry(s);
@@ -1248,8 +1310,6 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
ide_set_irq(s->bus);
break;
case IBM_SENSE_CONDITION:
- if (s->drive_kind != IDE_CFATA)
- goto abort_cmd;
switch (s->feature) {
case 0x01: /* sense temperature in device */
s->nsector = 0x50; /* +20 C */
@@ -1262,8 +1322,6 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
break;
case WIN_SMART:
- if (s->drive_kind == IDE_CD)
- goto abort_cmd;
if (s->hcyl != 0xc2 || s->lcyl != 0x4f)
goto abort_cmd;
if (!s->smart_enabled && s->feature != SMART_ENABLE)
@@ -1418,6 +1476,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
}
break;
default:
+ /* should not be reachable */
abort_cmd:
ide_abort_command(s);
ide_set_irq(s->bus);
@@ -1738,8 +1797,20 @@ void ide_bus_reset(IDEBus *bus)
bus->dma->ops->reset(bus->dma);
}
+static bool ide_cd_is_tray_open(void *opaque)
+{
+ return ((IDEState *)opaque)->tray_open;
+}
+
+static bool ide_cd_is_medium_locked(void *opaque)
+{
+ return ((IDEState *)opaque)->tray_locked;
+}
+
static const BlockDevOps ide_cd_block_ops = {
.change_media_cb = ide_cd_change_cb,
+ .is_tray_open = ide_cd_is_tray_open,
+ .is_medium_locked = ide_cd_is_medium_locked,
};
int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind,
@@ -1777,7 +1848,7 @@ int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind,
s->smart_selftest_count = 0;
if (kind == IDE_CD) {
bdrv_set_dev_ops(bs, &ide_cd_block_ops, s);
- bs->buffer_alignment = 2048;
+ bdrv_set_buffer_alignment(bs, 2048);
} else {
if (!bdrv_is_inserted(s->bs)) {
error_report("Device needs media, but drive is empty");
@@ -1801,7 +1872,6 @@ int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind,
}
ide_reset(s);
- bdrv_set_removable(bs, s->drive_kind == IDE_CD);
return 0;
}
@@ -1995,6 +2065,22 @@ static bool ide_drive_pio_state_needed(void *opaque)
|| (s->bus->error_status & BM_STATUS_PIO_RETRY);
}
+static int ide_tray_state_post_load(void *opaque, int version_id)
+{
+ IDEState *s = opaque;
+
+ bdrv_eject(s->bs, s->tray_open);
+ bdrv_lock_medium(s->bs, s->tray_locked);
+ return 0;
+}
+
+static bool ide_tray_state_needed(void *opaque)
+{
+ IDEState *s = opaque;
+
+ return s->tray_open || s->tray_locked;
+}
+
static bool ide_atapi_gesn_needed(void *opaque)
{
IDEState *s = opaque;
@@ -2022,6 +2108,19 @@ static const VMStateDescription vmstate_ide_atapi_gesn_state = {
}
};
+static const VMStateDescription vmstate_ide_tray_state = {
+ .name = "ide_drive/tray_state",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .post_load = ide_tray_state_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_BOOL(tray_open, IDEState),
+ VMSTATE_BOOL(tray_locked, IDEState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_ide_drive_pio_state = {
.name = "ide_drive/pio_state",
.version_id = 1,
@@ -2076,6 +2175,9 @@ const VMStateDescription vmstate_ide_drive = {
.vmsd = &vmstate_ide_drive_pio_state,
.needed = ide_drive_pio_state_needed,
}, {
+ .vmsd = &vmstate_ide_tray_state,
+ .needed = ide_tray_state_needed,
+ }, {
.vmsd = &vmstate_ide_atapi_gesn_state,
.needed = ide_atapi_gesn_needed,
}, {
diff --git a/hw/ide/ich.c b/hw/ide/ich.c
index 5278bc4d6c..0327d0ee72 100644
--- a/hw/ide/ich.c
+++ b/hw/ide/ich.c
@@ -66,7 +66,6 @@
#include <hw/pci.h>
#include <hw/isa.h>
#include "block.h"
-#include "block_int.h"
#include "dma.h"
#include <hw/ide/pci.h>
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index 111785294d..233915ce0d 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -7,7 +7,6 @@
* non-internal declarations are in hw/ide.h
*/
#include <hw/ide.h>
-#include "block_int.h"
#include "iorange.h"
#include "dma.h"
@@ -442,6 +441,8 @@ struct IDEState {
struct unreported_events events;
uint8_t sense_key;
uint8_t asc;
+ bool tray_open;
+ bool tray_locked;
uint8_t cdrom_changed;
int packet_transfer_size;
int elementary_transfer_size;
diff --git a/hw/ide/isa.c b/hw/ide/isa.c
index 4ac745324c..28b69d2cc3 100644
--- a/hw/ide/isa.c
+++ b/hw/ide/isa.c
@@ -26,7 +26,6 @@
#include <hw/pc.h>
#include <hw/isa.h>
#include "block.h"
-#include "block_int.h"
#include "dma.h"
#include <hw/ide/internal.h>
diff --git a/hw/ide/macio.c b/hw/ide/macio.c
index fdf5d75082..c1844cb738 100644
--- a/hw/ide/macio.c
+++ b/hw/ide/macio.c
@@ -26,7 +26,6 @@
#include <hw/ppc_mac.h>
#include <hw/mac_dbdma.h>
#include "block.h"
-#include "block_int.h"
#include "dma.h"
#include <hw/ide/internal.h>
diff --git a/hw/ide/microdrive.c b/hw/ide/microdrive.c
index 91c0e3c89d..9eee5b50ba 100644
--- a/hw/ide/microdrive.c
+++ b/hw/ide/microdrive.c
@@ -26,7 +26,6 @@
#include <hw/pc.h>
#include <hw/pcmcia.h>
#include "block.h"
-#include "block_int.h"
#include "dma.h"
#include <hw/ide/internal.h>
diff --git a/hw/ide/mmio.c b/hw/ide/mmio.c
index 132b7517ba..2ec21b0163 100644
--- a/hw/ide/mmio.c
+++ b/hw/ide/mmio.c
@@ -24,7 +24,6 @@
*/
#include <hw/hw.h>
#include "block.h"
-#include "block_int.h"
#include "dma.h"
#include <hw/ide/internal.h>
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index d1a14d7cc1..9fded02954 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -27,7 +27,6 @@
#include <hw/pci.h>
#include <hw/isa.h>
#include "block.h"
-#include "block_int.h"
#include "dma.h"
#include <hw/ide/pci.h>
diff --git a/hw/ide/via.c b/hw/ide/via.c
index c0b9d43827..dab8a39f57 100644
--- a/hw/ide/via.c
+++ b/hw/ide/via.c
@@ -28,7 +28,6 @@
#include <hw/pci.h>
#include <hw/isa.h>
#include "block.h"
-#include "block_int.h"
#include "sysemu.h"
#include "dma.h"
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index 1643a63ee8..dbb3bdf2ce 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -15,7 +15,6 @@
#include "hw.h"
#include "pci.h"
#include "scsi.h"
-#include "block_int.h"
//#define DEBUG_LSI
//#define DEBUG_LSI_REG
@@ -883,7 +882,6 @@ static void lsi_do_msgout(LSIState *s)
int len;
uint32_t current_tag;
lsi_request *current_req, *p, *p_next;
- int id;
if (s->current) {
current_tag = s->current->tag;
@@ -892,7 +890,6 @@ static void lsi_do_msgout(LSIState *s)
current_tag = s->select_tag;
current_req = lsi_find_by_tag(s, current_tag);
}
- id = (current_tag >> 8) & 0xf;
DPRINTF("MSG out len=%d\n", s->dbc);
while (s->dbc) {
@@ -977,9 +974,8 @@ static void lsi_do_msgout(LSIState *s)
device, but this is currently not implemented (and seems not
to be really necessary). So let's simply clear all queued
commands for the current device: */
- id = current_tag & 0x0000ff00;
QTAILQ_FOREACH_SAFE(p, &s->queue, next, p_next) {
- if ((p->tag & 0x0000ff00) == id) {
+ if ((p->tag & 0x0000ff00) == (current_tag & 0x0000ff00)) {
scsi_req_cancel(p->req);
}
}
diff --git a/hw/mips.h b/hw/mips.h
index 8ce41fc4be..6fa9a3ae75 100644
--- a/hw/mips.h
+++ b/hw/mips.h
@@ -8,9 +8,6 @@ PCIBus *gt64120_register(qemu_irq *pic);
/* bonito.c */
PCIBus *bonito_init(qemu_irq *pic);
-/* mipsnet.c */
-void mipsnet_init(int base, qemu_irq irq, NICInfo *nd);
-
/* jazz_led.c */
void jazz_led_init(target_phys_addr_t base);
diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c
index 0d46cc4c5a..ac65555b74 100644
--- a/hw/mips_mipssim.c
+++ b/hw/mips_mipssim.c
@@ -35,6 +35,8 @@
#include "mips-bios.h"
#include "loader.h"
#include "elf.h"
+#include "sysbus.h"
+#include "exec-memory.h"
static struct _loaderparams {
int ram_size;
@@ -112,6 +114,22 @@ static void main_cpu_reset(void *opaque)
}
}
+static void mipsnet_init(int base, qemu_irq irq, NICInfo *nd)
+{
+ DeviceState *dev;
+ SysBusDevice *s;
+
+ dev = qdev_create(NULL, "mipsnet");
+ qdev_set_nic_properties(dev, nd);
+ qdev_init_nofail(dev);
+
+ s = sysbus_from_qdev(dev);
+ sysbus_connect_irq(s, 0, irq);
+ memory_region_add_subregion(get_system_io(),
+ base,
+ sysbus_mmio_get_region(s, 0));
+}
+
static void
mips_mipssim_init (ram_addr_t ram_size,
const char *boot_device,
diff --git a/hw/mipsnet.c b/hw/mipsnet.c
index b889ee0062..605367bc5f 100644
--- a/hw/mipsnet.c
+++ b/hw/mipsnet.c
@@ -1,12 +1,7 @@
#include "hw.h"
-#include "mips.h"
#include "net.h"
-#include "isa.h"
-
-//#define DEBUG_MIPSNET_SEND
-//#define DEBUG_MIPSNET_RECEIVE
-//#define DEBUG_MIPSNET_DATA
-//#define DEBUG_MIPSNET_IRQ
+#include "trace.h"
+#include "sysbus.h"
/* MIPSnet register offsets */
@@ -25,6 +20,8 @@
#define MAX_ETH_FRAME_SIZE 1514
typedef struct MIPSnetState {
+ SysBusDevice busdev;
+
uint32_t busy;
uint32_t rx_count;
uint32_t rx_read;
@@ -33,7 +30,7 @@ typedef struct MIPSnetState {
uint32_t intctl;
uint8_t rx_buffer[MAX_ETH_FRAME_SIZE];
uint8_t tx_buffer[MAX_ETH_FRAME_SIZE];
- int io_base;
+ MemoryRegion io;
qemu_irq irq;
NICState *nic;
NICConf conf;
@@ -54,9 +51,7 @@ static void mipsnet_reset(MIPSnetState *s)
static void mipsnet_update_irq(MIPSnetState *s)
{
int isr = !!s->intctl;
-#ifdef DEBUG_MIPSNET_IRQ
- printf("mipsnet: Set IRQ to %d (%02x)\n", isr, s->intctl);
-#endif
+ trace_mipsnet_irq(isr, s->intctl);
qemu_set_irq(s->irq, isr);
}
@@ -80,9 +75,7 @@ static ssize_t mipsnet_receive(VLANClientState *nc, const uint8_t *buf, size_t s
{
MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
-#ifdef DEBUG_MIPSNET_RECEIVE
- printf("mipsnet: receiving len=%zu\n", size);
-#endif
+ trace_mipsnet_receive(size);
if (!mipsnet_can_receive(nc))
return -1;
@@ -103,7 +96,8 @@ static ssize_t mipsnet_receive(VLANClientState *nc, const uint8_t *buf, size_t s
return size;
}
-static uint32_t mipsnet_ioport_read(void *opaque, uint32_t addr)
+static uint64_t mipsnet_ioport_read(void *opaque, target_phys_addr_t addr,
+ unsigned int size)
{
MIPSnetState *s = opaque;
int ret = 0;
@@ -144,20 +138,17 @@ static uint32_t mipsnet_ioport_read(void *opaque, uint32_t addr)
default:
break;
}
-#ifdef DEBUG_MIPSNET_DATA
- printf("mipsnet: read addr=0x%02x val=0x%02x\n", addr, ret);
-#endif
+ trace_mipsnet_read(addr, ret);
return ret;
}
-static void mipsnet_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+static void mipsnet_ioport_write(void *opaque, target_phys_addr_t addr,
+ uint64_t val, unsigned int size)
{
MIPSnetState *s = opaque;
addr &= 0x3f;
-#ifdef DEBUG_MIPSNET_DATA
- printf("mipsnet: write addr=0x%02x val=0x%02x\n", addr, val);
-#endif
+ trace_mipsnet_write(addr, val);
switch (addr) {
case MIPSNET_TX_DATA_COUNT:
s->tx_count = (val <= MAX_ETH_FRAME_SIZE) ? val : 0;
@@ -181,9 +172,7 @@ static void mipsnet_ioport_write(void *opaque, uint32_t addr, uint32_t val)
s->tx_buffer[s->tx_written++] = val;
if (s->tx_written == s->tx_count) {
/* Send buffer. */
-#ifdef DEBUG_MIPSNET_SEND
- printf("mipsnet: sending len=%d\n", s->tx_count);
-#endif
+ trace_mipsnet_send(s->tx_count);
qemu_send_packet(&s->nic->nc, s->tx_buffer, s->tx_count);
s->tx_count = s->tx_written = 0;
s->intctl |= MIPSNET_INTCTL_TXDONE;
@@ -224,11 +213,7 @@ static void mipsnet_cleanup(VLANClientState *nc)
{
MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
- vmstate_unregister(NULL, &vmstate_mipsnet, s);
-
- isa_unassign_ioport(s->io_base, 36);
-
- g_free(s);
+ s->nic = NULL;
}
static NetClientInfo net_mipsnet_info = {
@@ -239,35 +224,50 @@ static NetClientInfo net_mipsnet_info = {
.cleanup = mipsnet_cleanup,
};
-void mipsnet_init (int base, qemu_irq irq, NICInfo *nd)
-{
- MIPSnetState *s;
-
- qemu_check_nic_model(nd, "mipsnet");
+static MemoryRegionOps mipsnet_ioport_ops = {
+ .read = mipsnet_ioport_read,
+ .write = mipsnet_ioport_write,
+ .impl.min_access_size = 1,
+ .impl.max_access_size = 4,
+};
- s = g_malloc0(sizeof(MIPSnetState));
+static int mipsnet_sysbus_init(SysBusDevice *dev)
+{
+ MIPSnetState *s = DO_UPCAST(MIPSnetState, busdev, dev);
- register_ioport_write(base, 36, 1, mipsnet_ioport_write, s);
- register_ioport_read(base, 36, 1, mipsnet_ioport_read, s);
- register_ioport_write(base, 36, 2, mipsnet_ioport_write, s);
- register_ioport_read(base, 36, 2, mipsnet_ioport_read, s);
- register_ioport_write(base, 36, 4, mipsnet_ioport_write, s);
- register_ioport_read(base, 36, 4, mipsnet_ioport_read, s);
+ memory_region_init_io(&s->io, &mipsnet_ioport_ops, s, "mipsnet-io", 36);
+ sysbus_init_mmio_region(dev, &s->io);
+ sysbus_init_irq(dev, &s->irq);
- s->io_base = base;
- s->irq = irq;
+ s->nic = qemu_new_nic(&net_mipsnet_info, &s->conf,
+ dev->qdev.info->name, dev->qdev.id, s);
+ qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
- if (nd) {
- s->conf.macaddr = nd->macaddr;
- s->conf.vlan = nd->vlan;
- s->conf.peer = nd->netdev;
+ return 0;
+}
- s->nic = qemu_new_nic(&net_mipsnet_info, &s->conf,
- nd->model, nd->name, s);
+static void mipsnet_sysbus_reset(DeviceState *dev)
+{
+ MIPSnetState *s = DO_UPCAST(MIPSnetState, busdev.qdev, dev);
+ mipsnet_reset(s);
+}
- qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
+static SysBusDeviceInfo mipsnet_info = {
+ .init = mipsnet_sysbus_init,
+ .qdev.name = "mipsnet",
+ .qdev.desc = "MIPS Simulator network device",
+ .qdev.size = sizeof(MIPSnetState),
+ .qdev.vmsd = &vmstate_mipsnet,
+ .qdev.reset = mipsnet_sysbus_reset,
+ .qdev.props = (Property[]) {
+ DEFINE_NIC_PROPERTIES(MIPSnetState, conf),
+ DEFINE_PROP_END_OF_LIST(),
}
+};
- mipsnet_reset(s);
- vmstate_register(NULL, 0, &vmstate_mipsnet, s);
+static void mipsnet_register_devices(void)
+{
+ sysbus_register_withprop(&mipsnet_info);
}
+
+device_init(mipsnet_register_devices)
diff --git a/hw/pci.c b/hw/pci.c
index 57ff7b1098..af7400374b 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -312,11 +312,6 @@ void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *qdev)
bus->hotplug_qdev = qdev;
}
-void pci_bus_set_mem_base(PCIBus *bus, target_phys_addr_t base)
-{
- bus->mem_base = base;
-}
-
PCIBus *pci_register_bus(DeviceState *parent, const char *name,
pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
void *irq_opaque,
@@ -833,12 +828,6 @@ PCIDevice *pci_register_device(PCIBus *bus, const char *name,
return pci_dev;
}
-static target_phys_addr_t pci_to_cpu_addr(PCIBus *bus,
- target_phys_addr_t addr)
-{
- return addr + bus->mem_base;
-}
-
static void pci_unregister_io_regions(PCIDevice *pci_dev)
{
PCIIORegion *r;
@@ -1066,8 +1055,7 @@ static void pci_update_mappings(PCIDevice *d)
1);
} else {
memory_region_add_subregion_overlap(r->address_space,
- pci_to_cpu_addr(d->bus,
- r->addr),
+ r->addr,
r->memory,
1);
}
diff --git a/hw/pci.h b/hw/pci.h
index 391217e431..c04b1693c3 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -255,8 +255,6 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name,
void pci_device_reset(PCIDevice *dev);
void pci_bus_reset(PCIBus *bus);
-void pci_bus_set_mem_base(PCIBus *bus, target_phys_addr_t base);
-
PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model,
const char *default_devaddr);
PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model,
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 160eaee693..02482947ca 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -772,6 +772,11 @@ const struct SCSISense sense_code_NO_MEDIUM = {
.key = NOT_READY, .asc = 0x3a, .ascq = 0x00
};
+/* LUN not ready, medium removal prevented */
+const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED = {
+ .key = NOT_READY, .asc = 0x53, .ascq = 0x00
+};
+
/* Hardware error, internal target failure */
const struct SCSISense sense_code_TARGET_FAILURE = {
.key = HARDWARE_ERROR, .asc = 0x44, .ascq = 0x00
@@ -807,6 +812,11 @@ const struct SCSISense sense_code_INCOMPATIBLE_MEDIUM = {
.key = ILLEGAL_REQUEST, .asc = 0x30, .ascq = 0x00
};
+/* Illegal request, medium removal prevented */
+const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED = {
+ .key = ILLEGAL_REQUEST, .asc = 0x53, .ascq = 0x00
+};
+
/* Command aborted, I/O process terminated */
const struct SCSISense sense_code_IO_ERROR = {
.key = ABORTED_COMMAND, .asc = 0x00, .ascq = 0x06
@@ -977,13 +987,11 @@ static const char *scsi_command_name(uint8_t cmd)
[ SYNCHRONIZE_CACHE_16 ] = "SYNCHRONIZE_CACHE_16",
[ LOCATE_16 ] = "LOCATE_16",
[ WRITE_SAME_16 ] = "WRITE_SAME_16",
- [ ERASE_16 ] = "ERASE_16",
+ /* ERASE_16 and WRITE_SAME_16 use the same operation code */
[ SERVICE_ACTION_IN_16 ] = "SERVICE_ACTION_IN_16",
[ WRITE_LONG_16 ] = "WRITE_LONG_16",
[ REPORT_LUNS ] = "REPORT_LUNS",
[ BLANK ] = "BLANK",
- [ MAINTENANCE_IN ] = "MAINTENANCE_IN",
- [ MAINTENANCE_OUT ] = "MAINTENANCE_OUT",
[ MOVE_MEDIUM ] = "MOVE_MEDIUM",
[ LOAD_UNLOAD ] = "LOAD_UNLOAD",
[ READ_12 ] = "READ_12",
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 9724d0fe9a..4a60820b18 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -37,6 +37,7 @@ do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
#include "scsi-defs.h"
#include "sysemu.h"
#include "blockdev.h"
+#include "block_int.h"
#define SCSI_DMA_BUF_SIZE 131072
#define SCSI_MAX_INQUIRY_LEN 256
@@ -72,6 +73,8 @@ struct SCSIDiskState
QEMUBH *bh;
char *version;
char *serial;
+ bool tray_open;
+ bool tray_locked;
};
static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type);
@@ -182,6 +185,9 @@ static void scsi_read_data(SCSIRequest *req)
if (n > SCSI_DMA_BUF_SIZE / 512)
n = SCSI_DMA_BUF_SIZE / 512;
+ if (s->tray_open) {
+ scsi_read_complete(r, -ENOMEDIUM);
+ }
r->iov.iov_len = n * 512;
qemu_iovec_init_external(&r->qiov, &r->iov, 1);
@@ -280,6 +286,9 @@ static void scsi_write_data(SCSIRequest *req)
n = r->iov.iov_len / 512;
if (n) {
+ if (s->tray_open) {
+ scsi_write_complete(r, -ENOMEDIUM);
+ }
qemu_iovec_init_external(&r->qiov, &r->iov, 1);
bdrv_acct_start(s->bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_WRITE);
@@ -664,7 +673,7 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
p[5] = 0xff; /* CD DA, DA accurate, RW supported,
RW corrected, C2 errors, ISRC,
UPC, Bar code */
- p[6] = 0x2d | (bdrv_is_locked(s->bs)? 2 : 0);
+ p[6] = 0x2d | (s->tray_locked ? 2 : 0);
/* Locking supported, jumper present, eject, tray */
p[7] = 0; /* no volume & mute control, no
changer */
@@ -814,6 +823,27 @@ static int scsi_disk_emulate_read_toc(SCSIRequest *req, uint8_t *outbuf)
return toclen;
}
+static int scsi_disk_emulate_start_stop(SCSIDiskReq *r)
+{
+ SCSIRequest *req = &r->req;
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
+ bool start = req->cmd.buf[4] & 1;
+ bool loej = req->cmd.buf[4] & 2; /* load on start, eject on !start */
+
+ if (s->qdev.type == TYPE_ROM && loej) {
+ if (!start && !s->tray_open && s->tray_locked) {
+ scsi_check_condition(r,
+ bdrv_is_inserted(s->bs)
+ ? SENSE_CODE(ILLEGAL_REQ_REMOVAL_PREVENTED)
+ : SENSE_CODE(NOT_READY_REMOVAL_PREVENTED));
+ return -1;
+ }
+ bdrv_eject(s->bs, !start);
+ s->tray_open = !start;
+ }
+ return 0;
+}
+
static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
{
SCSIRequest *req = &r->req;
@@ -823,7 +853,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
switch (req->cmd.buf[0]) {
case TEST_UNIT_READY:
- if (!bdrv_is_inserted(s->bs))
+ if (s->tray_open || !bdrv_is_inserted(s->bs))
goto not_ready;
break;
case INQUIRY:
@@ -859,13 +889,13 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
goto illegal_request;
break;
case START_STOP:
- if (s->qdev.type == TYPE_ROM && (req->cmd.buf[4] & 2)) {
- /* load/eject medium */
- bdrv_eject(s->bs, !(req->cmd.buf[4] & 1));
+ if (scsi_disk_emulate_start_stop(r) < 0) {
+ return -1;
}
break;
case ALLOW_MEDIUM_REMOVAL:
- bdrv_set_locked(s->bs, req->cmd.buf[4] & 1);
+ s->tray_locked = req->cmd.buf[4] & 1;
+ bdrv_lock_medium(s->bs, req->cmd.buf[4] & 1);
break;
case READ_CAPACITY_10:
/* The normal LEN field for this command is zero. */
@@ -946,7 +976,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
return buflen;
not_ready:
- if (!bdrv_is_inserted(s->bs)) {
+ if (s->tray_open || !bdrv_is_inserted(s->bs)) {
scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
} else {
scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY));
@@ -1143,6 +1173,27 @@ static void scsi_destroy(SCSIDevice *dev)
blockdev_mark_auto_del(s->qdev.conf.bs);
}
+static void scsi_cd_change_media_cb(void *opaque, bool load)
+{
+ ((SCSIDiskState *)opaque)->tray_open = !load;
+}
+
+static bool scsi_cd_is_tray_open(void *opaque)
+{
+ return ((SCSIDiskState *)opaque)->tray_open;
+}
+
+static bool scsi_cd_is_medium_locked(void *opaque)
+{
+ return ((SCSIDiskState *)opaque)->tray_locked;
+}
+
+static const BlockDevOps scsi_cd_block_ops = {
+ .change_media_cb = scsi_cd_change_media_cb,
+ .is_tray_open = scsi_cd_is_tray_open,
+ .is_medium_locked = scsi_cd_is_medium_locked,
+};
+
static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
{
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
@@ -1177,6 +1228,7 @@ static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
}
if (scsi_type == TYPE_ROM) {
+ bdrv_set_dev_ops(s->bs, &scsi_cd_block_ops, s);
s->qdev.blocksize = 2048;
} else if (scsi_type == TYPE_DISK) {
s->qdev.blocksize = s->qdev.conf.logical_block_size;
@@ -1185,11 +1237,10 @@ static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
return -1;
}
s->cluster_size = s->qdev.blocksize / 512;
- s->bs->buffer_alignment = s->qdev.blocksize;
+ bdrv_set_buffer_alignment(s->bs, s->qdev.blocksize);
s->qdev.type = scsi_type;
qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
- bdrv_set_removable(s->bs, scsi_type == TYPE_ROM);
add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, ",0");
return 0;
}
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index cb5d4f125d..5ce01afdce 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -450,7 +450,6 @@ static int scsi_generic_initfn(SCSIDevice *dev)
}
}
DPRINTF("block size %d\n", s->qdev.blocksize);
- bdrv_set_removable(s->bs, 0);
return 0;
}
diff --git a/hw/scsi.h b/hw/scsi.h
index 98fd689859..e8dcabfa28 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -3,7 +3,6 @@
#include "qdev.h"
#include "block.h"
-#include "block_int.h"
#define MAX_SCSI_DEVS 255
@@ -136,6 +135,8 @@ extern const struct SCSISense sense_code_NO_SENSE;
extern const struct SCSISense sense_code_LUN_NOT_READY;
/* LUN not ready, Medium not present */
extern const struct SCSISense sense_code_NO_MEDIUM;
+/* LUN not ready, medium removal prevented */
+extern const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED;
/* Hardware error, internal target failure */
extern const struct SCSISense sense_code_TARGET_FAILURE;
/* Illegal request, invalid command operation code */
@@ -150,6 +151,8 @@ extern const struct SCSISense sense_code_LUN_NOT_SUPPORTED;
extern const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED;
/* Illegal request, Incompatible format */
extern const struct SCSISense sense_code_INCOMPATIBLE_FORMAT;
+/* Illegal request, medium removal prevented */
+extern const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED;
/* Command aborted, I/O process terminated */
extern const struct SCSISense sense_code_IO_ERROR;
/* Command aborted, I_T Nexus loss occurred */
diff --git a/hw/sd.c b/hw/sd.c
index 1af62b23c6..10e26ade58 100644
--- a/hw/sd.c
+++ b/hw/sd.c
@@ -419,7 +419,7 @@ static void sd_reset(SDState *sd, BlockDriverState *bdrv)
sd->pwd_len = 0;
}
-static void sd_cardchange(void *opaque)
+static void sd_cardchange(void *opaque, bool load)
{
SDState *sd = opaque;
diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c
index 072a88a382..5f8f4bdb9f 100644
--- a/hw/virtio-balloon.c
+++ b/hw/virtio-balloon.c
@@ -303,6 +303,8 @@ VirtIODevice *virtio_balloon_init(DeviceState *dev)
void virtio_balloon_exit(VirtIODevice *vdev)
{
VirtIOBalloon *s = DO_UPCAST(VirtIOBalloon, vdev, vdev);
+
+ qemu_remove_balloon_handler(s);
unregister_savevm(s->qdev, "virtio-balloon", s);
virtio_cleanup(vdev);
}
diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index 4df23f4228..c2ee0001eb 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -11,7 +11,7 @@
*
*/
-#include <qemu-common.h>
+#include "qemu-common.h"
#include "qemu-error.h"
#include "trace.h"
#include "blockdev.h"
@@ -599,9 +599,8 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf,
s->qdev = dev;
register_savevm(dev, "virtio-blk", virtio_blk_id++, 2,
virtio_blk_save, virtio_blk_load, s);
- bdrv_set_removable(s->bs, 0);
bdrv_set_dev_ops(s->bs, &virtio_block_ops, s);
- s->bs->buffer_alignment = conf->logical_block_size;
+ bdrv_set_buffer_alignment(s->bs, conf->logical_block_size);
add_boot_device_path(conf->bootindex, dev, "/disk@0,0");
diff --git a/hw/virtio.h b/hw/virtio.h
index c1292647fe..4d20d9b8f4 100644
--- a/hw/virtio.h
+++ b/hw/virtio.h
@@ -18,7 +18,7 @@
#include "net.h"
#include "qdev.h"
#include "sysemu.h"
-#include "block_int.h"
+#include "block.h"
#include "event_notifier.h"
#ifdef CONFIG_LINUX
#include "9p.h"
diff --git a/hw/xen_backend.c b/hw/xen_backend.c
index aa642675f8..d876cabb12 100644
--- a/hw/xen_backend.c
+++ b/hw/xen_backend.c
@@ -421,13 +421,13 @@ static int xen_be_try_init(struct XenDevice *xendev)
}
/*
- * Try to connect xendev. Depends on the frontend being ready
+ * Try to initialise xendev. Depends on the frontend being ready
* for it (shared ring and evtchn info in xenstore, state being
* Initialised or Connected).
*
* Goes to Connected on success.
*/
-static int xen_be_try_connect(struct XenDevice *xendev)
+static int xen_be_try_initialise(struct XenDevice *xendev)
{
int rc = 0;
@@ -441,11 +441,11 @@ static int xen_be_try_connect(struct XenDevice *xendev)
}
}
- if (xendev->ops->connect) {
- rc = xendev->ops->connect(xendev);
+ if (xendev->ops->initialise) {
+ rc = xendev->ops->initialise(xendev);
}
if (rc != 0) {
- xen_be_printf(xendev, 0, "connect() failed\n");
+ xen_be_printf(xendev, 0, "initialise() failed\n");
return rc;
}
@@ -454,6 +454,29 @@ static int xen_be_try_connect(struct XenDevice *xendev)
}
/*
+ * Try to let xendev know that it is connected. Depends on the
+ * frontend being Connected. Note that this may be called more
+ * than once since the backend state is not modified.
+ */
+static void xen_be_try_connected(struct XenDevice *xendev)
+{
+ if (!xendev->ops->connected) {
+ return;
+ }
+
+ if (xendev->fe_state != XenbusStateConnected) {
+ if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) {
+ xen_be_printf(xendev, 2, "frontend not ready, ignoring\n");
+ } else {
+ xen_be_printf(xendev, 2, "frontend not ready (yet)\n");
+ return;
+ }
+ }
+
+ xendev->ops->connected(xendev);
+}
+
+/*
* Teardown connection.
*
* Goes to Closed when done.
@@ -508,7 +531,12 @@ void xen_be_check_state(struct XenDevice *xendev)
rc = xen_be_try_init(xendev);
break;
case XenbusStateInitWait:
- rc = xen_be_try_connect(xendev);
+ rc = xen_be_try_initialise(xendev);
+ break;
+ case XenbusStateConnected:
+ /* xendev->be_state doesn't change */
+ xen_be_try_connected(xendev);
+ rc = -1;
break;
case XenbusStateClosed:
rc = xen_be_try_reset(xendev);
diff --git a/hw/xen_backend.h b/hw/xen_backend.h
index 6401c85a7e..3305630903 100644
--- a/hw/xen_backend.h
+++ b/hw/xen_backend.h
@@ -21,7 +21,8 @@ struct XenDevOps {
uint32_t flags;
void (*alloc)(struct XenDevice *xendev);
int (*init)(struct XenDevice *xendev);
- int (*connect)(struct XenDevice *xendev);
+ int (*initialise)(struct XenDevice *xendev);
+ void (*connected)(struct XenDevice *xendev);
void (*event)(struct XenDevice *xendev);
void (*disconnect)(struct XenDevice *xendev);
int (*free)(struct XenDevice *xendev);
diff --git a/hw/xen_console.c b/hw/xen_console.c
index 5789bd09a5..edcb31ce66 100644
--- a/hw/xen_console.c
+++ b/hw/xen_console.c
@@ -212,7 +212,7 @@ out:
return ret;
}
-static int con_connect(struct XenDevice *xendev)
+static int con_initialise(struct XenDevice *xendev)
{
struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
int limit;
@@ -273,7 +273,7 @@ struct XenDevOps xen_console_ops = {
.size = sizeof(struct XenConsole),
.flags = DEVOPS_FLAG_IGNORE_STATE,
.init = con_init,
- .connect = con_connect,
+ .initialise = con_initialise,
.event = con_event,
.disconnect = con_disconnect,
};
diff --git a/hw/xen_disk.c b/hw/xen_disk.c
index da531a67dd..8a9fac499b 100644
--- a/hw/xen_disk.c
+++ b/hw/xen_disk.c
@@ -852,7 +852,7 @@ struct XenDevOps xen_blkdev_ops = {
.flags = DEVOPS_FLAG_NEED_GNTDEV,
.alloc = blk_alloc,
.init = blk_init,
- .connect = blk_connect,
+ .initialise = blk_connect,
.disconnect = blk_disconnect,
.event = blk_event,
.free = blk_free,
diff --git a/hw/xen_nic.c b/hw/xen_nic.c
index b28b15670b..aeca8da96b 100644
--- a/hw/xen_nic.c
+++ b/hw/xen_nic.c
@@ -433,7 +433,7 @@ struct XenDevOps xen_netdev_ops = {
.size = sizeof(struct XenNetDev),
.flags = DEVOPS_FLAG_NEED_GNTDEV,
.init = net_init,
- .connect = net_connect,
+ .initialise = net_connect,
.event = net_event,
.disconnect = net_disconnect,
.free = net_free,
diff --git a/hw/xenfb.c b/hw/xenfb.c
index d532d3e898..1bcf171b01 100644
--- a/hw/xenfb.c
+++ b/hw/xenfb.c
@@ -351,15 +351,11 @@ static int input_init(struct XenDevice *xendev)
return 0;
}
-static int input_connect(struct XenDevice *xendev)
+static int input_initialise(struct XenDevice *xendev)
{
struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
int rc;
- if (xenstore_read_fe_int(xendev, "request-abs-pointer",
- &in->abs_pointer_wanted) == -1)
- in->abs_pointer_wanted = 0;
-
if (!in->c.ds) {
char *vfb = xenstore_read_str(NULL, "device/vfb");
if (vfb == NULL) {
@@ -377,10 +373,24 @@ static int input_connect(struct XenDevice *xendev)
return rc;
qemu_add_kbd_event_handler(xenfb_key_event, in);
+ return 0;
+}
+
+static void input_connected(struct XenDevice *xendev)
+{
+ struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
+
+ if (xenstore_read_fe_int(xendev, "request-abs-pointer",
+ &in->abs_pointer_wanted) == -1) {
+ in->abs_pointer_wanted = 0;
+ }
+
+ if (in->qmouse) {
+ qemu_remove_mouse_event_handler(in->qmouse);
+ }
in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in,
in->abs_pointer_wanted,
"Xen PVFB Mouse");
- return 0;
}
static void input_disconnect(struct XenDevice *xendev)
@@ -865,7 +875,7 @@ static int fb_init(struct XenDevice *xendev)
return 0;
}
-static int fb_connect(struct XenDevice *xendev)
+static int fb_initialise(struct XenDevice *xendev)
{
struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
struct xenfb_page *fb_page;
@@ -959,7 +969,8 @@ static void fb_event(struct XenDevice *xendev)
struct XenDevOps xen_kbdmouse_ops = {
.size = sizeof(struct XenInput),
.init = input_init,
- .connect = input_connect,
+ .initialise = input_initialise,
+ .connected = input_connected,
.disconnect = input_disconnect,
.event = input_event,
};
@@ -967,7 +978,7 @@ struct XenDevOps xen_kbdmouse_ops = {
struct XenDevOps xen_framebuffer_ops = {
.size = sizeof(struct XenFB),
.init = fb_init,
- .connect = fb_connect,
+ .initialise = fb_initialise,
.disconnect = fb_disconnect,
.event = fb_event,
.frontend_changed = fb_frontend_changed,
diff --git a/hw/xtensa_dc232b.c b/hw/xtensa_dc232b.c
new file mode 100644
index 0000000000..015d6aaa6b
--- /dev/null
+++ b/hw/xtensa_dc232b.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Open Source and Linux Lab nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "sysemu.h"
+#include "boards.h"
+#include "loader.h"
+#include "elf.h"
+#include "memory.h"
+#include "exec-memory.h"
+
+static uint64_t translate_phys_addr(void *env, uint64_t addr)
+{
+ return cpu_get_phys_page_debug(env, addr);
+}
+
+static void dc232b_reset(void *env)
+{
+ cpu_reset(env);
+}
+
+static void dc232b_init(ram_addr_t ram_size,
+ const char *boot_device,
+ const char *kernel_filename, const char *kernel_cmdline,
+ const char *initrd_filename, const char *cpu_model)
+{
+ CPUState *env = NULL;
+ MemoryRegion *ram, *rom;
+ int n;
+
+ for (n = 0; n < smp_cpus; n++) {
+ env = cpu_init(cpu_model);
+ if (!env) {
+ fprintf(stderr, "Unable to find CPU definition\n");
+ exit(1);
+ }
+ env->sregs[PRID] = n;
+ qemu_register_reset(dc232b_reset, env);
+ /* Need MMU initialized prior to ELF loading,
+ * so that ELF gets loaded into virtual addresses
+ */
+ dc232b_reset(env);
+ }
+
+ ram = g_malloc(sizeof(*ram));
+ memory_region_init_ram(ram, NULL, "xtensa.sram", ram_size);
+ memory_region_add_subregion(get_system_memory(), 0, ram);
+
+ rom = g_malloc(sizeof(*rom));
+ memory_region_init_ram(rom, NULL, "xtensa.rom", 0x1000);
+ memory_region_add_subregion(get_system_memory(), 0xfe000000, rom);
+
+ if (kernel_filename) {
+ uint64_t elf_entry;
+ uint64_t elf_lowaddr;
+#ifdef TARGET_WORDS_BIGENDIAN
+ int success = load_elf(kernel_filename, translate_phys_addr, env,
+ &elf_entry, &elf_lowaddr, NULL, 1, ELF_MACHINE, 0);
+#else
+ int success = load_elf(kernel_filename, translate_phys_addr, env,
+ &elf_entry, &elf_lowaddr, NULL, 0, ELF_MACHINE, 0);
+#endif
+ if (success > 0) {
+ env->pc = elf_entry;
+ }
+ }
+}
+
+static void xtensa_dc232b_init(ram_addr_t ram_size,
+ const char *boot_device,
+ const char *kernel_filename, const char *kernel_cmdline,
+ const char *initrd_filename, const char *cpu_model)
+{
+ if (!cpu_model) {
+ cpu_model = "dc232b";
+ }
+ dc232b_init(ram_size, boot_device, kernel_filename, kernel_cmdline,
+ initrd_filename, cpu_model);
+}
+
+static QEMUMachine xtensa_dc232b_machine = {
+ .name = "dc232b",
+ .desc = "Diamond 232L Standard Core Rev.B (LE) (dc232b)",
+ .init = xtensa_dc232b_init,
+ .max_cpus = 4,
+};
+
+static void xtensa_dc232b_machine_init(void)
+{
+ qemu_register_machine(&xtensa_dc232b_machine);
+}
+
+machine_init(xtensa_dc232b_machine_init);
diff --git a/hw/xtensa_pic.c b/hw/xtensa_pic.c
new file mode 100644
index 0000000000..3033ae214a
--- /dev/null
+++ b/hw/xtensa_pic.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Open Source and Linux Lab nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "hw.h"
+#include "pc.h"
+#include "qemu-log.h"
+#include "qemu-timer.h"
+
+/* Stub functions for hardware that doesn't exist. */
+void pic_info(Monitor *mon)
+{
+}
+
+void irq_info(Monitor *mon)
+{
+}
+
+void xtensa_advance_ccount(CPUState *env, uint32_t d)
+{
+ uint32_t old_ccount = env->sregs[CCOUNT];
+
+ env->sregs[CCOUNT] += d;
+
+ if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) {
+ int i;
+ for (i = 0; i < env->config->nccompare; ++i) {
+ if (env->sregs[CCOMPARE + i] - old_ccount <= d) {
+ xtensa_timer_irq(env, i, 1);
+ }
+ }
+ }
+}
+
+void check_interrupts(CPUState *env)
+{
+ int minlevel = xtensa_get_cintlevel(env);
+ uint32_t int_set_enabled = env->sregs[INTSET] & env->sregs[INTENABLE];
+ int level;
+
+ /* If the CPU is halted advance CCOUNT according to the vm_clock time
+ * elapsed since the moment when it was advanced last time.
+ */
+ if (env->halted) {
+ int64_t now = qemu_get_clock_ns(vm_clock);
+
+ xtensa_advance_ccount(env,
+ muldiv64(now - env->halt_clock,
+ env->config->clock_freq_khz, 1000000));
+ env->halt_clock = now;
+ }
+ for (level = env->config->nlevel; level > minlevel; --level) {
+ if (env->config->level_mask[level] & int_set_enabled) {
+ env->pending_irq_level = level;
+ cpu_interrupt(env, CPU_INTERRUPT_HARD);
+ qemu_log_mask(CPU_LOG_INT,
+ "%s level = %d, cintlevel = %d, "
+ "pc = %08x, a0 = %08x, ps = %08x, "
+ "intset = %08x, intenable = %08x, "
+ "ccount = %08x\n",
+ __func__, level, xtensa_get_cintlevel(env),
+ env->pc, env->regs[0], env->sregs[PS],
+ env->sregs[INTSET], env->sregs[INTENABLE],
+ env->sregs[CCOUNT]);
+ return;
+ }
+ }
+ env->pending_irq_level = 0;
+ cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+}
+
+static void xtensa_set_irq(void *opaque, int irq, int active)
+{
+ CPUState *env = opaque;
+
+ if (irq >= env->config->ninterrupt) {
+ qemu_log("%s: bad IRQ %d\n", __func__, irq);
+ } else {
+ uint32_t irq_bit = 1 << irq;
+
+ if (active) {
+ env->sregs[INTSET] |= irq_bit;
+ } else if (env->config->interrupt[irq].inttype == INTTYPE_LEVEL) {
+ env->sregs[INTSET] &= ~irq_bit;
+ }
+
+ check_interrupts(env);
+ }
+}
+
+void xtensa_timer_irq(CPUState *env, uint32_t id, uint32_t active)
+{
+ qemu_set_irq(env->irq_inputs[env->config->timerint[id]], active);
+}
+
+static void xtensa_ccompare_cb(void *opaque)
+{
+ CPUState *env = opaque;
+ xtensa_advance_ccount(env, env->wake_ccount - env->sregs[CCOUNT]);
+}
+
+void xtensa_irq_init(CPUState *env)
+{
+ env->irq_inputs = (void **)qemu_allocate_irqs(
+ xtensa_set_irq, env, env->config->ninterrupt);
+ if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT) &&
+ env->config->nccompare > 0) {
+ env->ccompare_timer =
+ qemu_new_timer_ns(vm_clock, &xtensa_ccompare_cb, env);
+ }
+}
diff --git a/hw/xtensa_sample.c b/hw/xtensa_sample.c
new file mode 100644
index 0000000000..31a6f70825
--- /dev/null
+++ b/hw/xtensa_sample.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Open Source and Linux Lab nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "sysemu.h"
+#include "boards.h"
+#include "loader.h"
+#include "elf.h"
+#include "memory.h"
+#include "exec-memory.h"
+
+static void xtensa_sample_reset(void *env)
+{
+ cpu_reset(env);
+}
+
+static void xtensa_init(ram_addr_t ram_size,
+ const char *boot_device,
+ const char *kernel_filename, const char *kernel_cmdline,
+ const char *initrd_filename, const char *cpu_model)
+{
+ CPUState *env = NULL;
+ MemoryRegion *ram;
+ const size_t dram_size = 0x10000;
+ const size_t iram_size = 0x20000;
+ int n;
+
+ for (n = 0; n < smp_cpus; n++) {
+ env = cpu_init(cpu_model);
+ if (!env) {
+ fprintf(stderr, "Unable to find CPU definition\n");
+ exit(1);
+ }
+ qemu_register_reset(xtensa_sample_reset, env);
+ env->sregs[PRID] = n;
+ }
+
+ ram = g_malloc(sizeof(*ram));
+ memory_region_init_ram(ram, NULL, "xtensa.ram",
+ dram_size + iram_size + ram_size);
+ memory_region_add_subregion(get_system_memory(),
+ 0x60000000 - dram_size - iram_size, ram);
+
+ if (kernel_filename) {
+ uint64_t elf_entry;
+ uint64_t elf_lowaddr;
+#ifdef TARGET_WORDS_BIGENDIAN
+ int success = load_elf(kernel_filename, NULL, NULL, &elf_entry,
+ &elf_lowaddr, NULL, 1, ELF_MACHINE, 0);
+#else
+ int success = load_elf(kernel_filename, NULL, NULL, &elf_entry,
+ &elf_lowaddr, NULL, 0, ELF_MACHINE, 0);
+#endif
+ if (success > 0) {
+ env->pc = elf_entry;
+ }
+ }
+}
+
+static void xtensa_sample_init(ram_addr_t ram_size,
+ const char *boot_device,
+ const char *kernel_filename, const char *kernel_cmdline,
+ const char *initrd_filename, const char *cpu_model)
+{
+ if (!cpu_model) {
+ cpu_model = "sample-xtensa-core";
+ }
+ xtensa_init(ram_size, boot_device, kernel_filename, kernel_cmdline,
+ initrd_filename, cpu_model);
+}
+
+static QEMUMachine xtensa_sample_machine = {
+ .name = "sample-xtensa-machine",
+ .desc = "Sample Xtensa machine (sample Xtensa core)",
+ .init = xtensa_sample_init,
+ .max_cpus = 4,
+};
+
+static void xtensa_sample_machine_init(void)
+{
+ qemu_register_machine(&xtensa_sample_machine);
+}
+
+machine_init(xtensa_sample_machine_init);