diff --git a/block/blkmemory.c b/block/blkmemory.c new file mode 100644 index 0000000000..d7f998cbcd --- /dev/null +++ b/block/blkmemory.c @@ -0,0 +1,152 @@ +/* + * MemoryRegion backed block driver + * + * Copyright (c) 2013 espes + * + * Based on "Add an in-memory block device" patch + * Copyright IBM, Corp. 2007 + * Authors: + * Anthony Liguori + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "qemu/osdep.h" +#include "qemu/cutils.h" + +#include "exec/memory.h" +#include "block/block_int.h" + +#include "block/blkmemory.h" + +#define DEBUG_BLKMEMORY + +typedef struct BDRVMemoryState { + uint64_t size; + AddressSpace *as; +} BDRVMemoryState; + +static int memory_open(BlockDriverState *bs, QDict *options, int flags, + Error **errp) +{ + /* We're kinda unique in that we're inited with a MemoryRegion instead + * of a file. A MemoryRegion pointer can't be put in QDict, so we have + * to be inited by hand. If something tries to init us normally, better + * to fail than crash. + */ + return -1; +} + +// FIXME: crash on close +static void memory_close(BlockDriverState *bs) +{ + /* nothing to do..? */ +} + +static int64_t memory_getlength(BlockDriverState *bs) +{ + BDRVMemoryState *s = bs->opaque; + + return s->size / BDRV_SECTOR_SIZE; +} + +static int memory_read(BlockDriverState *bs, int64_t offset, + int64_t bytes, QEMUIOVector *qiov, + BdrvRequestFlags flags) +{ + BDRVMemoryState *s = bs->opaque; + uint64_t sector_num = offset >> BDRV_SECTOR_BITS; + int nb_sectors = bytes >> BDRV_SECTOR_BITS; + uint8_t *buf; + void *orig_buf; + +#ifdef DEBUG_BLKMEMORY + printf("blkmemory read 0x%llx : %d\n", sector_num, nb_sectors); +#endif + + sector_num = MIN(sector_num, bs->total_sectors - 1); + size_t size = MIN(s->size - sector_num * BDRV_SECTOR_SIZE, + nb_sectors * BDRV_SECTOR_SIZE); + + address_space_read(s->as, sector_num * BDRV_SECTOR_SIZE, MEMTXATTRS_UNSPECIFIED, buf, size); + qemu_iovec_from_buf(qiov, 0, buf, size); + + return 0; +} + +static int memory_write(BlockDriverState *bs, + int64_t offset, int64_t bytes, + QEMUIOVector *qiov, + BdrvRequestFlags flags) +{ + BDRVMemoryState *s = bs->opaque; + uint64_t sector_num = offset >> BDRV_SECTOR_BITS; + int nb_sectors = bytes >> BDRV_SECTOR_BITS; + uint8_t *buf; + void *orig_buf; + +#ifdef DEBUG_BLKMEMORY + printf("blkmemory write 0x%llx : %d\n", sector_num, nb_sectors); +#endif + + sector_num = MIN(sector_num, bs->total_sectors - 1); + size_t size = MIN(s->size - sector_num * BDRV_SECTOR_SIZE, + nb_sectors * BDRV_SECTOR_SIZE); + + address_space_write(s->as, sector_num * BDRV_SECTOR_SIZE, MEMTXATTRS_UNSPECIFIED, qiov->iov, size); + + return 0; +} + +static BlockDriver bdrv_memory = { + .format_name = "memory", + .instance_size = sizeof(BDRVMemoryState), + .bdrv_open = memory_open, + .bdrv_close = memory_close, + .bdrv_co_getlength = memory_getlength, + + // FIXME: Is this what we want? What's the difference between CO and AIO? + .bdrv_co_preadv = memory_read, + .bdrv_co_pwritev = memory_write, +}; + +static void bdrv_memory_init(void) +{ + bdrv_register(&bdrv_memory); +} + +block_init(bdrv_memory_init); + + +int bdrv_memory_open(BlockDriverState *bs, AddressSpace *as, uint64_t size) +{ + bs->total_sectors = (size + BDRV_SECTOR_SIZE-1) / BDRV_SECTOR_SIZE; + //bs->read_only = false; + //bs->is_temporary = false; + bs->encrypted = false; + + pstrcpy(bs->filename, sizeof(bs->filename), ""); + + bs->drv = &bdrv_memory; + bs->opaque = g_malloc0(bdrv_memory.instance_size); + if (!bs->opaque) { + return -1; + } + + BDRVMemoryState *s = bs->opaque; + s->as = as; + s->size = size; + + return 0; +} diff --git a/block/meson.build b/block/meson.build index f1262ec2ba..1f783e4a3d 100644 --- a/block/meson.build +++ b/block/meson.build @@ -39,6 +39,7 @@ block_ss.add(files( 'throttle.c', 'throttle-groups.c', 'write-threshold.c', + 'blkmemory.c', ), zstd, zlib) system_ss.add(when: 'CONFIG_TCG', if_true: files('blkreplay.c')) diff --git a/hw/xbox/chihiro.c b/hw/xbox/chihiro.c index 9bae859945..8abc9bdb47 100644 --- a/hw/xbox/chihiro.c +++ b/hw/xbox/chihiro.c @@ -83,97 +83,6 @@ typedef struct ChihiroMachineClass { /*< public >*/ } ChihiroMachineClass; - - -#define SEGA_CHIP_REVISION 0xF0 -# define SEGA_CHIP_REVISION_CHIP_ID 0xFF00 -# define SEGA_CHIP_REVISION_FPGA_CHIP_ID 0x0000 -# define SEGA_CHIP_REVISION_ASIC_CHIP_ID 0x0100 -# define SEGA_CHIP_REVISION_REVISION_ID_MASK 0x00FF -#define SEGA_DIMM_SIZE 0xF4 -# define SEGA_DIMM_SIZE_128M 0 -# define SEGA_DIMM_SIZE_256M 1 -# define SEGA_DIMM_SIZE_512M 2 -# define SEGA_DIMM_SIZE_1024M 3 - -//#define DEBUG_CHIHIRO - -typedef struct ChihiroLPCState { - ISADevice dev; - MemoryRegion ioport; -} ChihiroLPCState; - -#define CHIHIRO_LPC_DEVICE(obj) \ - OBJECT_CHECK(ChihiroLPCState, (obj), "chihiro-lpc") - - -static uint64_t chhiro_lpc_io_read(void *opaque, hwaddr addr, - unsigned size) -{ - uint64_t r = 0; - switch (addr) { - case SEGA_CHIP_REVISION: - r = SEGA_CHIP_REVISION_ASIC_CHIP_ID; - break; - case SEGA_DIMM_SIZE: - r = SEGA_DIMM_SIZE_128M; - break; - } -#ifdef DEBUG_CHIHIRO - printf("chihiro lpc read [0x%llx] -> 0x%llx\n", addr, r); -#endif - return r; -} - -static void chhiro_lpc_io_write(void *opaque, hwaddr addr, uint64_t val, - unsigned size) -{ -#ifdef DEBUG_CHIHIRO - printf("chihiro lpc write [0x%llx] = 0x%llx\n", addr, val); -#endif -} - -static const MemoryRegionOps chihiro_lpc_io_ops = { - .read = chhiro_lpc_io_read, - .write = chhiro_lpc_io_write, - .impl = { - .min_access_size = 2, - .max_access_size = 2, - }, -}; - -static void chihiro_lpc_realize(DeviceState *dev, Error **errp) -{ - ChihiroLPCState *s = CHIHIRO_LPC_DEVICE(dev); - ISADevice *isa = ISA_DEVICE(dev); - - memory_region_init_io(&s->ioport, OBJECT(dev), &chihiro_lpc_io_ops, s, - "chihiro-lpc-io", 0x100); - isa_register_ioport(isa, &s->ioport, 0x4000); -} - -static void chihiro_lpc_class_initfn(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - dc->realize = chihiro_lpc_realize; - dc->desc = "Chihiro LPC"; -} - -static const TypeInfo chihiro_lpc_info = { - .name = "chihiro-lpc", - .parent = TYPE_ISA_DEVICE, - .instance_size = sizeof(ChihiroLPCState), - .class_init = chihiro_lpc_class_initfn, -}; - -static void chihiro_register_types(void) -{ - type_register_static(&chihiro_lpc_info); -} - -type_init(chihiro_register_types) - - /* The chihiro baseboard communicates with the xbox by acting as an IDE * device. The device maps the boot rom from the mediaboard, a communication * area for interfacing with the network board, and the ram on the baseboard. @@ -285,7 +194,7 @@ static void chihiro_init(MachineState *machine) ISABus *isa_bus; xbox_init_common(machine, NULL, &isa_bus); - isa_create_simple(isa_bus, "chihiro-lpc"); + isa_create_simple(isa_bus, "lpcsega"); } static void chihiro_machine_options(MachineClass *m) diff --git a/hw/xbox/lpcsega.c b/hw/xbox/lpcsega.c new file mode 100644 index 0000000000..049644149d --- /dev/null +++ b/hw/xbox/lpcsega.c @@ -0,0 +1,138 @@ +/* + * QEMU Chihiro emulation + * + * Copyright (c) 2013 espes + * Copyright (c) 2018-2021 Matt Borgerson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "qemu/osdep.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" +#include "migration/vmstate.h" +#include "sysemu/sysemu.h" +#include "hw/char/serial.h" +#include "hw/isa/isa.h" +#include "qapi/error.h" + +#define SEGA_CHIP_REVISION 0xF0 +# define SEGA_CHIP_REVISION_CHIP_ID 0xFF00 +# define SEGA_CHIP_REVISION_FPGA_CHIP_ID 0x0000 +# define SEGA_CHIP_REVISION_ASIC_CHIP_ID 0x0100 +# define SEGA_CHIP_REVISION_REVISION_ID_MASK 0x00FF +#define SEGA_DIMM_SIZE 0xF4 +# define SEGA_DIMM_SIZE_128M 0 +# define SEGA_DIMM_SIZE_256M 1 +# define SEGA_DIMM_SIZE_512M 2 +# define SEGA_DIMM_SIZE_1024M 3 + +#define TYPE_ISA_LPCSEGA_DEVICE "lpcsega" +#define ISA_LPCSEGA_DEVICE(obj) \ + OBJECT_CHECK(ISALPCSEGAState, (obj), TYPE_ISA_LPCSEGA_DEVICE) + +#define DEBUG_SEGA +#ifdef DEBUG_SEGA +# define DPRINTF(format, ...) printf(format, ## __VA_ARGS__) +#else +# define DPRINTF(format, ...) do { } while (0) +#endif + +typedef struct LPCSEGAState { + MemoryRegion io; +} LPCSEGAState; + +typedef struct ISALPCSEGAState { + ISADevice parent_obj; + + bool sysopt; + uint16_t iobase; + LPCSEGAState state; +} ISALPCSEGAState; + +static void lpcsega_io_write(void *opaque, hwaddr addr, uint64_t val, + unsigned int size) +{ + DPRINTF("lpcsega io write 0x%02" HWADDR_PRIx " = 0x%02" PRIx64 "\n", addr, val); +} + +static uint64_t lpcsega_io_read(void *opaque, hwaddr addr, unsigned int size) +{ + uint32_t val = 0; + + switch (addr) { + case SEGA_CHIP_REVISION: + val = SEGA_CHIP_REVISION_ASIC_CHIP_ID; + break; + case SEGA_DIMM_SIZE: + val = SEGA_DIMM_SIZE_128M; + break; + } + + DPRINTF("lpcsega io read 0x%02" HWADDR_PRIx " -> 0x%02x\n", addr, val); + + return val; +} + +static const MemoryRegionOps lpcsega_io_ops = { + .read = lpcsega_io_read, + .write = lpcsega_io_write, + .valid = { + .min_access_size = 2, + .max_access_size = 2, + }, +}; + +static void lpcsega_realize(DeviceState *dev, Error **errp) +{ + ISADevice *isadev = ISA_DEVICE(dev); + ISALPCSEGAState *isa = ISA_LPCSEGA_DEVICE(isadev); + LPCSEGAState *s = &isa->state; + + memory_region_init_io(&s->io, OBJECT(dev), &lpcsega_io_ops, s, + "lpcsega-io", 0x100); + isa_register_ioport(isadev, &s->io, 0x4000); +} + +static Property lpcsega_properties[] = { + DEFINE_PROP_BOOL("sysopt", ISALPCSEGAState, sysopt, false), + DEFINE_PROP_END_OF_LIST(), +}; + +static void lpcsega_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = lpcsega_realize; + device_class_set_props(dc, lpcsega_properties); +} + +static void lpcsega_initfn(Object *o) +{ +} + +static const TypeInfo lpcsega_type_info = { + .name = TYPE_ISA_LPCSEGA_DEVICE, + .parent = TYPE_ISA_DEVICE, + .instance_init = lpcsega_initfn, + .instance_size = sizeof(ISALPCSEGAState), + .class_init = lpcsega_class_init, +}; + +static void lpcsega_register_types(void) +{ + type_register_static(&lpcsega_type_info); +} + +type_init(lpcsega_register_types) diff --git a/hw/xbox/meson.build b/hw/xbox/meson.build index dce2d3729e..f07706cb1b 100644 --- a/hw/xbox/meson.build +++ b/hw/xbox/meson.build @@ -5,6 +5,7 @@ specific_ss.add(files( # 'chihiro.c', 'eeprom_generation.c', 'lpc47m157.c', + 'lpcsega.c', 'nvnet.c', 'smbus_adm1032.c', 'smbus_cx25871.c', diff --git a/hw/xbox/smbus_xbox_smc.c b/hw/xbox/smbus_xbox_smc.c index 0695589bbd..299346149a 100644 --- a/hw/xbox/smbus_xbox_smc.c +++ b/hw/xbox/smbus_xbox_smc.c @@ -352,6 +352,7 @@ void xbox_smc_eject_button(void) // interaction. void xbox_smc_update_tray_state(void) { +#ifndef CHIHIRO Object *obj = object_resolve_path_type("", TYPE_XBOX_SMC, NULL); SMBusSMCDevice *smc = XBOX_SMC(obj); @@ -371,4 +372,5 @@ void xbox_smc_update_tray_state(void) } xbox_assert_extsmi(); +#endif } diff --git a/include/block/blkmemory.h b/include/block/blkmemory.h new file mode 100644 index 0000000000..04e5b1fc28 --- /dev/null +++ b/include/block/blkmemory.h @@ -0,0 +1,9 @@ +#ifndef BLKMEMORY_H +#define BLKMEMORY_H + +#include "block/block_int.h" +#include "exec/memory.h" + +int bdrv_memory_open(BlockDriverState *bs, AddressSpace *as, uint64_t size); + +#endif diff --git a/system/vl.c b/system/vl.c index 580d0cfd28..f4affca5d4 100644 --- a/system/vl.c +++ b/system/vl.c @@ -2981,6 +2981,7 @@ void qemu_init(int argc, char **argv) } } +#ifndef CHIHIRO // Always populate DVD drive. If disc path is the empty string, drive is // connected but no media present. fake_argv[fake_argc++] = strdup("-drive"); @@ -2988,6 +2989,7 @@ void qemu_init(int argc, char **argv) fake_argv[fake_argc++] = g_strdup_printf("index=1,media=cdrom,file=%s", escaped_dvd_path); free(escaped_dvd_path); +#endif fake_argv[fake_argc++] = strdup("-display"); fake_argv[fake_argc++] = strdup("xemu");