diff options
Diffstat (limited to 'hw')
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; } @@ -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); } } @@ -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); } } @@ -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) @@ -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); } @@ -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; } @@ -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 */ @@ -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); |