Browse Source

Add Macintosh Quadra 800 machine in hw/m68k

-----BEGIN PGP SIGNATURE-----
 
 iQJGBAABCAAwFiEEzS913cjjpNwuT1Fz8ww4vT8vvjwFAl23MAESHGxhdXJlbnRA
 dml2aWVyLmV1AAoJEPMMOL0/L748UPQQAIfzpB0KRb7InPFNUgGvShoCwKXQmbZm
 wkYoPdDnzgy3FBdbkFM0YcvvSH7Cnbq1njwaTOp8li+NBBiyZCqbCMBKLOusKqhR
 tlP/vF/Jj+o7pbggS+ruSYTtT0+4Q8T5AKEmWmm6ga+PhpT8kFCL+jC8j5bUTmDX
 0lTGwzANDNjGllP+aS6qhY1j9PEWcUpOWr42hW9ZXhAStsPOSzaV7SAZ2XZKPVJz
 KSdnsCPHJVzF4Ps6QK9iMw8szVGat/fq8UU/9w1o2HkmkTRNRW6vuagxmAG1iheW
 fPSpxNnXtoZqTY/qSP9/mMv8cntOtV5YjA/fAeSBa24vY/JFE/zstOrWUY0yhV2y
 CdllFzd/4duR5EThIatJZ4CE3ye89O4or73706l6fnpCI6+UADbneI+0I6VV0fyJ
 I+BxokoI4IgheYOkxD/oxGVx14Ax5vI+R4DkJ09m2koL9h/mALXKeKjb277sJJA/
 GrRx9ttdCGYp7beD84u38aSvNZ9Cs3foljBIYKH6/GqUY5Hl1FlFPE5cDRa+p/yR
 UA/ZDZ4FnJkyhg6Y5mrE8Fx7dvax+9QapKhPqeC9uEuLvUz8yPquMcICx8ehRnNx
 bl0IISTDZvIJwb8ZzemvWHPz63GfQzD1nJjxLZ8c4Q4XYtktETr45tYJd61vuV8x
 gzf/MzaBXSkX
 =HLjK
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/vivier/tags/q800-branch-pull-request' into staging

Add Macintosh Quadra 800 machine in hw/m68k

# gpg: Signature made Mon 28 Oct 2019 18:14:25 GMT
# gpg:                using RSA key CD2F75DDC8E3A4DC2E4F5173F30C38BD3F2FBE3C
# gpg:                issuer "laurent@vivier.eu"
# gpg: Good signature from "Laurent Vivier <lvivier@redhat.com>" [full]
# gpg:                 aka "Laurent Vivier <laurent@vivier.eu>" [full]
# gpg:                 aka "Laurent Vivier (Red Hat) <lvivier@redhat.com>" [full]
# Primary key fingerprint: CD2F 75DD C8E3 A4DC 2E4F  5173 F30C 38BD 3F2F BE3C

* remotes/vivier/tags/q800-branch-pull-request:
  BootLinuxConsoleTest: Test the Quadra 800
  hw/m68k: define Macintosh Quadra 800
  hw/m68k: add a dummy SWIM floppy controller
  hw/m68k: add Nubus macfb video card
  hw/m68k: add Nubus support
  hw/m68k: implement ADB bus support for via
  hw/m68k: add VIA support
  dp8393x: manage big endian bus
  esp: add pseudo-DMA as used by Macintosh
  esp: move get_cmd() post-DMA code to get_cmd_cb()
  esp: move handle_ti_cmd() cleanup code to esp_do_dma().

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
stable-4.2
Peter Maydell 2 years ago
parent
commit
f724de8dde
35 changed files with 3659 additions and 61 deletions
  1. +14
    -0
      MAINTAINERS
  2. +4
    -0
      arch_init.c
  3. +1
    -0
      default-configs/m68k-softmmu.mak
  4. +1
    -0
      hw/Kconfig
  5. +1
    -0
      hw/Makefile.objs
  6. +3
    -0
      hw/block/Kconfig
  7. +1
    -0
      hw/block/Makefile.objs
  8. +489
    -0
      hw/block/swim.c
  9. +5
    -0
      hw/display/Kconfig
  10. +1
    -0
      hw/display/Makefile.objs
  11. +477
    -0
      hw/display/macfb.c
  12. +10
    -0
      hw/m68k/Kconfig
  13. +1
    -0
      hw/m68k/Makefile.objs
  14. +114
    -0
      hw/m68k/bootinfo.h
  15. +401
    -0
      hw/m68k/q800.c
  16. +5
    -0
      hw/misc/Kconfig
  17. +1
    -0
      hw/misc/Makefile.objs
  18. +964
    -0
      hw/misc/mac_via.c
  19. +57
    -31
      hw/net/dp8393x.c
  20. +2
    -0
      hw/nubus/Kconfig
  21. +4
    -0
      hw/nubus/Makefile.objs
  22. +45
    -0
      hw/nubus/mac-nubus-bridge.c
  23. +34
    -0
      hw/nubus/nubus-bridge.c
  24. +111
    -0
      hw/nubus/nubus-bus.c
  25. +215
    -0
      hw/nubus/nubus-device.c
  26. +308
    -28
      hw/scsi/esp.c
  27. +76
    -0
      include/hw/block/swim.h
  28. +64
    -0
      include/hw/display/macfb.h
  29. +115
    -0
      include/hw/misc/mac_via.h
  30. +24
    -0
      include/hw/nubus/mac-nubus-bridge.h
  31. +69
    -0
      include/hw/nubus/nubus.h
  32. +15
    -0
      include/hw/scsi/esp.h
  33. +1
    -1
      qemu-options.hx
  34. +24
    -0
      tests/acceptance/boot_linux_console.py
  35. +2
    -1
      vl.c

+ 14
- 0
MAINTAINERS View File

@ -917,6 +917,20 @@ F: hw/m68k/next-*.c
F: hw/display/next-fb.c
F: include/hw/m68k/next-cube.h
q800
M: Laurent Vivier <laurent@vivier.eu>
S: Maintained
F: hw/m68k/q800.c
F: hw/misc/mac_via.c
F: hw/nubus/*
F: hw/display/macfb.c
F: hw/block/swim.c
F: hw/m68k/bootinfo.h
F: include/hw/misc/mac_via.h
F: include/hw/nubus/*
F: include/hw/display/macfb.h
F: include/hw/block/swim.h
MicroBlaze Machines
-------------------
petalogix_s3adsp1800


+ 4
- 0
arch_init.c View File

@ -38,6 +38,10 @@
int graphic_width = 1024;
int graphic_height = 768;
int graphic_depth = 8;
#elif defined(TARGET_M68K)
int graphic_width = 800;
int graphic_height = 600;
int graphic_depth = 8;
#else
int graphic_width = 800;
int graphic_height = 600;


+ 1
- 0
default-configs/m68k-softmmu.mak View File

@ -7,3 +7,4 @@ CONFIG_SEMIHOSTING=y
CONFIG_AN5206=y
CONFIG_MCF5208=y
CONFIG_NEXTCUBE=y
CONFIG_Q800=y

+ 1
- 0
hw/Kconfig View File

@ -21,6 +21,7 @@ source isa/Kconfig
source mem/Kconfig
source misc/Kconfig
source net/Kconfig
source nubus/Kconfig
source nvram/Kconfig
source pci-bridge/Kconfig
source pci-host/Kconfig


+ 1
- 0
hw/Makefile.objs View File

@ -38,6 +38,7 @@ devices-dirs-y += virtio/
devices-dirs-y += watchdog/
devices-dirs-y += xen/
devices-dirs-$(CONFIG_MEM_DEVICE) += mem/
devices-dirs-$(CONFIG_NUBUS) += nubus/
devices-dirs-y += semihosting/
devices-dirs-y += smbios/
endif


+ 3
- 0
hw/block/Kconfig View File

@ -37,3 +37,6 @@ config VHOST_USER_BLK
# Only PCI devices are provided for now
default y if VIRTIO_PCI
depends on VIRTIO && VHOST_USER && LINUX
config SWIM
bool

+ 1
- 0
hw/block/Makefile.objs View File

@ -8,6 +8,7 @@ common-obj-$(CONFIG_XEN) += xen-block.o
common-obj-$(CONFIG_ECC) += ecc.o
common-obj-$(CONFIG_ONENAND) += onenand.o
common-obj-$(CONFIG_NVME_PCI) += nvme.o
common-obj-$(CONFIG_SWIM) += swim.o
obj-$(CONFIG_SH4) += tc58128.o


+ 489
- 0
hw/block/swim.c View File

@ -0,0 +1,489 @@
/*
* QEMU Macintosh floppy disk controller emulator (SWIM)
*
* Copyright (c) 2014-2018 Laurent Vivier <laurent@vivier.eu>
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*
* Only the basic support: it allows to switch from IWM (Integrated WOZ
* Machine) mode to the SWIM mode and makes the linux driver happy.
*/
#include "qemu/osdep.h"
#include "qemu/main-loop.h"
#include "qapi/error.h"
#include "sysemu/block-backend.h"
#include "hw/sysbus.h"
#include "migration/vmstate.h"
#include "hw/block/block.h"
#include "hw/block/swim.h"
#include "hw/qdev-properties.h"
/* IWM registers */
#define IWM_PH0L 0
#define IWM_PH0H 1
#define IWM_PH1L 2
#define IWM_PH1H 3
#define IWM_PH2L 4
#define IWM_PH2H 5
#define IWM_PH3L 6
#define IWM_PH3H 7
#define IWM_MTROFF 8
#define IWM_MTRON 9
#define IWM_INTDRIVE 10
#define IWM_EXTDRIVE 11
#define IWM_Q6L 12
#define IWM_Q6H 13
#define IWM_Q7L 14
#define IWM_Q7H 15
/* SWIM registers */
#define SWIM_WRITE_DATA 0
#define SWIM_WRITE_MARK 1
#define SWIM_WRITE_CRC 2
#define SWIM_WRITE_PARAMETER 3
#define SWIM_WRITE_PHASE 4
#define SWIM_WRITE_SETUP 5
#define SWIM_WRITE_MODE0 6
#define SWIM_WRITE_MODE1 7
#define SWIM_READ_DATA 8
#define SWIM_READ_MARK 9
#define SWIM_READ_ERROR 10
#define SWIM_READ_PARAMETER 11
#define SWIM_READ_PHASE 12
#define SWIM_READ_SETUP 13
#define SWIM_READ_STATUS 14
#define SWIM_READ_HANDSHAKE 15
#define REG_SHIFT 9
#define SWIM_MODE_IWM 0
#define SWIM_MODE_SWIM 1
/* bits in phase register */
#define SWIM_SEEK_NEGATIVE 0x074
#define SWIM_STEP 0x071
#define SWIM_MOTOR_ON 0x072
#define SWIM_MOTOR_OFF 0x076
#define SWIM_INDEX 0x073
#define SWIM_EJECT 0x077
#define SWIM_SETMFM 0x171
#define SWIM_SETGCR 0x175
#define SWIM_RELAX 0x033
#define SWIM_LSTRB 0x008
#define SWIM_CA_MASK 0x077
/* Select values for swim_select and swim_readbit */
#define SWIM_READ_DATA_0 0x074
#define SWIM_TWOMEG_DRIVE 0x075
#define SWIM_SINGLE_SIDED 0x076
#define SWIM_DRIVE_PRESENT 0x077
#define SWIM_DISK_IN 0x170
#define SWIM_WRITE_PROT 0x171
#define SWIM_TRACK_ZERO 0x172
#define SWIM_TACHO 0x173
#define SWIM_READ_DATA_1 0x174
#define SWIM_MFM_MODE 0x175
#define SWIM_SEEK_COMPLETE 0x176
#define SWIM_ONEMEG_MEDIA 0x177
/* Bits in handshake register */
#define SWIM_MARK_BYTE 0x01
#define SWIM_CRC_ZERO 0x02
#define SWIM_RDDATA 0x04
#define SWIM_SENSE 0x08
#define SWIM_MOTEN 0x10
#define SWIM_ERROR 0x20
#define SWIM_DAT2BYTE 0x40
#define SWIM_DAT1BYTE 0x80
/* bits in setup register */
#define SWIM_S_INV_WDATA 0x01
#define SWIM_S_3_5_SELECT 0x02
#define SWIM_S_GCR 0x04
#define SWIM_S_FCLK_DIV2 0x08
#define SWIM_S_ERROR_CORR 0x10
#define SWIM_S_IBM_DRIVE 0x20
#define SWIM_S_GCR_WRITE 0x40
#define SWIM_S_TIMEOUT 0x80
/* bits in mode register */
#define SWIM_CLFIFO 0x01
#define SWIM_ENBL1 0x02
#define SWIM_ENBL2 0x04
#define SWIM_ACTION 0x08
#define SWIM_WRITE_MODE 0x10
#define SWIM_HEDSEL 0x20
#define SWIM_MOTON 0x80
static void fd_recalibrate(FDrive *drive)
{
}
static void swim_change_cb(void *opaque, bool load, Error **errp)
{
FDrive *drive = opaque;
if (!load) {
blk_set_perm(drive->blk, 0, BLK_PERM_ALL, &error_abort);
} else {
if (!blkconf_apply_backend_options(drive->conf,
blk_is_read_only(drive->blk), false,
errp)) {
return;
}
}
}
static const BlockDevOps swim_block_ops = {
.change_media_cb = swim_change_cb,
};
static Property swim_drive_properties[] = {
DEFINE_PROP_INT32("unit", SWIMDrive, unit, -1),
DEFINE_BLOCK_PROPERTIES(SWIMDrive, conf),
DEFINE_PROP_END_OF_LIST(),
};
static void swim_drive_realize(DeviceState *qdev, Error **errp)
{
SWIMDrive *dev = SWIM_DRIVE(qdev);
SWIMBus *bus = SWIM_BUS(qdev->parent_bus);
FDrive *drive;
int ret;
if (dev->unit == -1) {
for (dev->unit = 0; dev->unit < SWIM_MAX_FD; dev->unit++) {
drive = &bus->ctrl->drives[dev->unit];
if (!drive->blk) {
break;
}
}
}
if (dev->unit >= SWIM_MAX_FD) {
error_setg(errp, "Can't create floppy unit %d, bus supports "
"only %d units", dev->unit, SWIM_MAX_FD);
return;
}
drive = &bus->ctrl->drives[dev->unit];
if (drive->blk) {
error_setg(errp, "Floppy unit %d is in use", dev->unit);
return;
}
if (!dev->conf.blk) {
/* Anonymous BlockBackend for an empty drive */
dev->conf.blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
ret = blk_attach_dev(dev->conf.blk, qdev);
assert(ret == 0);
}
blkconf_blocksizes(&dev->conf);
if (dev->conf.logical_block_size != 512 ||
dev->conf.physical_block_size != 512)
{
error_setg(errp, "Physical and logical block size must "
"be 512 for floppy");
return;
}
/*
* rerror/werror aren't supported by fdc and therefore not even registered
* with qdev. So set the defaults manually before they are used in
* blkconf_apply_backend_options().
*/
dev->conf.rerror = BLOCKDEV_ON_ERROR_AUTO;
dev->conf.werror = BLOCKDEV_ON_ERROR_AUTO;
if (!blkconf_apply_backend_options(&dev->conf,
blk_is_read_only(dev->conf.blk),
false, errp)) {
return;
}
/*
* 'enospc' is the default for -drive, 'report' is what blk_new() gives us
* for empty drives.
*/
if (blk_get_on_error(dev->conf.blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC &&
blk_get_on_error(dev->conf.blk, 0) != BLOCKDEV_ON_ERROR_REPORT) {
error_setg(errp, "fdc doesn't support drive option werror");
return;
}
if (blk_get_on_error(dev->conf.blk, 1) != BLOCKDEV_ON_ERROR_REPORT) {
error_setg(errp, "fdc doesn't support drive option rerror");
return;
}
drive->conf = &dev->conf;
drive->blk = dev->conf.blk;
drive->swimctrl = bus->ctrl;
blk_set_dev_ops(drive->blk, &swim_block_ops, drive);
}
static void swim_drive_class_init(ObjectClass *klass, void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
k->realize = swim_drive_realize;
set_bit(DEVICE_CATEGORY_STORAGE, k->categories);
k->bus_type = TYPE_SWIM_BUS;
k->props = swim_drive_properties;
k->desc = "virtual SWIM drive";
}
static const TypeInfo swim_drive_info = {
.name = TYPE_SWIM_DRIVE,
.parent = TYPE_DEVICE,
.instance_size = sizeof(SWIMDrive),
.class_init = swim_drive_class_init,
};
static const TypeInfo swim_bus_info = {
.name = TYPE_SWIM_BUS,
.parent = TYPE_BUS,
.instance_size = sizeof(SWIMBus),
};
static void iwmctrl_write(void *opaque, hwaddr reg, uint64_t value,
unsigned size)
{
SWIMCtrl *swimctrl = opaque;
reg >>= REG_SHIFT;
swimctrl->regs[reg >> 1] = reg & 1;
if (swimctrl->regs[IWM_Q6] &&
swimctrl->regs[IWM_Q7]) {
if (swimctrl->regs[IWM_MTR]) {
/* data register */
swimctrl->iwm_data = value;
} else {
/* mode register */
swimctrl->iwm_mode = value;
/* detect sequence to switch from IWM mode to SWIM mode */
switch (swimctrl->iwm_switch) {
case 0:
if (value == 0x57) {
swimctrl->iwm_switch++;
}
break;
case 1:
if (value == 0x17) {
swimctrl->iwm_switch++;
}
break;
case 2:
if (value == 0x57) {
swimctrl->iwm_switch++;
}
break;
case 3:
if (value == 0x57) {
swimctrl->mode = SWIM_MODE_SWIM;
swimctrl->iwm_switch = 0;
}
break;
}
}
}
}
static uint64_t iwmctrl_read(void *opaque, hwaddr reg, unsigned size)
{
SWIMCtrl *swimctrl = opaque;
reg >>= REG_SHIFT;
swimctrl->regs[reg >> 1] = reg & 1;
return 0;
}
static void swimctrl_write(void *opaque, hwaddr reg, uint64_t value,
unsigned size)
{
SWIMCtrl *swimctrl = opaque;
if (swimctrl->mode == SWIM_MODE_IWM) {
iwmctrl_write(opaque, reg, value, size);
return;
}
reg >>= REG_SHIFT;
switch (reg) {
case SWIM_WRITE_PHASE:
swimctrl->swim_phase = value;
break;
case SWIM_WRITE_MODE0:
swimctrl->swim_mode &= ~value;
break;
case SWIM_WRITE_MODE1:
swimctrl->swim_mode |= value;
break;
case SWIM_WRITE_DATA:
case SWIM_WRITE_MARK:
case SWIM_WRITE_CRC:
case SWIM_WRITE_PARAMETER:
case SWIM_WRITE_SETUP:
break;
}
}
static uint64_t swimctrl_read(void *opaque, hwaddr reg, unsigned size)
{
SWIMCtrl *swimctrl = opaque;
uint32_t value = 0;
if (swimctrl->mode == SWIM_MODE_IWM) {
return iwmctrl_read(opaque, reg, size);
}
reg >>= REG_SHIFT;
switch (reg) {
case SWIM_READ_PHASE:
value = swimctrl->swim_phase;
break;
case SWIM_READ_HANDSHAKE:
if (swimctrl->swim_phase == SWIM_DRIVE_PRESENT) {
/* always answer "no drive present" */
value = SWIM_SENSE;
}
break;
case SWIM_READ_DATA:
case SWIM_READ_MARK:
case SWIM_READ_ERROR:
case SWIM_READ_PARAMETER:
case SWIM_READ_SETUP:
case SWIM_READ_STATUS:
break;
}
return value;
}
static const MemoryRegionOps swimctrl_mem_ops = {
.write = swimctrl_write,
.read = swimctrl_read,
.endianness = DEVICE_NATIVE_ENDIAN,
};
static void sysbus_swim_reset(DeviceState *d)
{
SWIM *sys = SWIM(d);
SWIMCtrl *ctrl = &sys->ctrl;
int i;
ctrl->mode = 0;
ctrl->iwm_switch = 0;
for (i = 0; i < 8; i++) {
ctrl->regs[i] = 0;
}
ctrl->iwm_data = 0;
ctrl->iwm_mode = 0;
ctrl->swim_phase = 0;
ctrl->swim_mode = 0;
for (i = 0; i < SWIM_MAX_FD; i++) {
fd_recalibrate(&ctrl->drives[i]);
}
}
static void sysbus_swim_init(Object *obj)
{
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
SWIM *sbs = SWIM(obj);
SWIMCtrl *swimctrl = &sbs->ctrl;
memory_region_init_io(&swimctrl->iomem, obj, &swimctrl_mem_ops, swimctrl,
"swim", 0x2000);
sysbus_init_mmio(sbd, &swimctrl->iomem);
}
static void sysbus_swim_realize(DeviceState *dev, Error **errp)
{
SWIM *sys = SWIM(dev);
SWIMCtrl *swimctrl = &sys->ctrl;
qbus_create_inplace(&swimctrl->bus, sizeof(SWIMBus), TYPE_SWIM_BUS, dev,
NULL);
swimctrl->bus.ctrl = swimctrl;
}
static const VMStateDescription vmstate_fdrive = {
.name = "fdrive",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_END_OF_LIST()
},
};
static const VMStateDescription vmstate_swim = {
.name = "swim",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_INT32(mode, SWIMCtrl),
/* IWM mode */
VMSTATE_INT32(iwm_switch, SWIMCtrl),
VMSTATE_UINT16_ARRAY(regs, SWIMCtrl, 8),
VMSTATE_UINT8(iwm_data, SWIMCtrl),
VMSTATE_UINT8(iwm_mode, SWIMCtrl),
/* SWIM mode */
VMSTATE_UINT8(swim_phase, SWIMCtrl),
VMSTATE_UINT8(swim_mode, SWIMCtrl),
/* Drives */
VMSTATE_STRUCT_ARRAY(drives, SWIMCtrl, SWIM_MAX_FD, 1,
vmstate_fdrive, FDrive),
VMSTATE_END_OF_LIST()
},
};
static const VMStateDescription vmstate_sysbus_swim = {
.name = "SWIM",
.version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_STRUCT(ctrl, SWIM, 0, vmstate_swim, SWIMCtrl),
VMSTATE_END_OF_LIST()
}
};
static void sysbus_swim_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = sysbus_swim_realize;
dc->reset = sysbus_swim_reset;
dc->vmsd = &vmstate_sysbus_swim;
}
static const TypeInfo sysbus_swim_info = {
.name = TYPE_SWIM,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(SWIM),
.instance_init = sysbus_swim_init,
.class_init = sysbus_swim_class_init,
};
static void swim_register_types(void)
{
type_register_static(&sysbus_swim_info);
type_register_static(&swim_bus_info);
type_register_static(&swim_drive_info);
}
type_init(swim_register_types)

+ 5
- 0
hw/display/Kconfig View File

@ -132,3 +132,8 @@ config ATI_VGA
select VGA
select BITBANG_I2C
select DDC
config MACFB
bool
select FRAMEBUFFER
depends on NUBUS

+ 1
- 0
hw/display/Makefile.objs View File

@ -26,6 +26,7 @@ common-obj-$(CONFIG_EXYNOS4) += exynos4210_fimd.o
common-obj-$(CONFIG_FRAMEBUFFER) += framebuffer.o
obj-$(CONFIG_MILKYMIST) += milkymist-vgafb.o
common-obj-$(CONFIG_ZAURUS) += tc6393xb.o
common-obj-$(CONFIG_MACFB) += macfb.o
obj-$(CONFIG_MILKYMIST_TMU2) += milkymist-tmu2.o
milkymist-tmu2.o-cflags := $(X11_CFLAGS) $(OPENGL_CFLAGS)


+ 477
- 0
hw/display/macfb.c View File

@ -0,0 +1,477 @@
/*
* QEMU Motorola 680x0 Macintosh Video Card Emulation
* Copyright (c) 2012-2018 Laurent Vivier
*
* some parts from QEMU G364 framebuffer Emulator.
* Copyright (c) 2007-2011 Herve Poussineau
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*
*/
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "hw/sysbus.h"
#include "ui/console.h"
#include "ui/pixel_ops.h"
#include "hw/nubus/nubus.h"
#include "hw/display/macfb.h"
#include "qapi/error.h"
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
#define VIDEO_BASE 0x00001000
#define DAFB_BASE 0x00800000
#define MACFB_PAGE_SIZE 4096
#define MACFB_VRAM_SIZE (4 * MiB)
#define DAFB_RESET 0x200
#define DAFB_LUT 0x213
typedef void macfb_draw_line_func(MacfbState *s, uint8_t *d, uint32_t addr,
int width);
static inline uint8_t macfb_read_byte(MacfbState *s, uint32_t addr)
{
return s->vram[addr & s->vram_bit_mask];
}
/* 1-bit color */
static void macfb_draw_line1(MacfbState *s, uint8_t *d, uint32_t addr,
int width)
{
uint8_t r, g, b;
int x;
for (x = 0; x < width; x++) {
int bit = x & 7;
int idx = (macfb_read_byte(s, addr) >> (7 - bit)) & 1;
r = g = b = ((1 - idx) << 7);
addr += (bit == 7);
*(uint32_t *)d = rgb_to_pixel32(r, g, b);
d += 4;
}
}
/* 2-bit color */
static void macfb_draw_line2(MacfbState *s, uint8_t *d, uint32_t addr,
int width)
{
uint8_t r, g, b;
int x;
for (x = 0; x < width; x++) {
int bit = (x & 3);
int idx = (macfb_read_byte(s, addr) >> ((3 - bit) << 1)) & 3;
r = s->color_palette[idx * 3];
g = s->color_palette[idx * 3 + 1];
b = s->color_palette[idx * 3 + 2];
addr += (bit == 3);
*(uint32_t *)d = rgb_to_pixel32(r, g, b);
d += 4;
}
}
/* 4-bit color */
static void macfb_draw_line4(MacfbState *s, uint8_t *d, uint32_t addr,
int width)
{
uint8_t r, g, b;
int x;
for (x = 0; x < width; x++) {
int bit = x & 1;
int idx = (macfb_read_byte(s, addr) >> ((1 - bit) << 2)) & 15;
r = s->color_palette[idx * 3];
g = s->color_palette[idx * 3 + 1];
b = s->color_palette[idx * 3 + 2];
addr += (bit == 1);
*(uint32_t *)d = rgb_to_pixel32(r, g, b);
d += 4;
}
}
/* 8-bit color */
static void macfb_draw_line8(MacfbState *s, uint8_t *d, uint32_t addr,
int width)
{
uint8_t r, g, b;
int x;
for (x = 0; x < width; x++) {
r = s->color_palette[macfb_read_byte(s, addr) * 3];
g = s->color_palette[macfb_read_byte(s, addr) * 3 + 1];
b = s->color_palette[macfb_read_byte(s, addr) * 3 + 2];
addr++;
*(uint32_t *)d = rgb_to_pixel32(r, g, b);
d += 4;
}
}
/* 16-bit color */
static void macfb_draw_line16(MacfbState *s, uint8_t *d, uint32_t addr,
int width)
{
uint8_t r, g, b;
int x;
for (x = 0; x < width; x++) {
uint16_t pixel;
pixel = (macfb_read_byte(s, addr) << 8) | macfb_read_byte(s, addr + 1);
r = ((pixel >> 10) & 0x1f) << 3;
g = ((pixel >> 5) & 0x1f) << 3;
b = (pixel & 0x1f) << 3;
addr += 2;
*(uint32_t *)d = rgb_to_pixel32(r, g, b);
d += 4;
}
}
/* 24-bit color */
static void macfb_draw_line24(MacfbState *s, uint8_t *d, uint32_t addr,
int width)
{
uint8_t r, g, b;
int x;
for (x = 0; x < width; x++) {
r = macfb_read_byte(s, addr);
g = macfb_read_byte(s, addr + 1);
b = macfb_read_byte(s, addr + 2);
addr += 3;
*(uint32_t *)d = rgb_to_pixel32(r, g, b);
d += 4;
}
}
enum {
MACFB_DRAW_LINE1,
MACFB_DRAW_LINE2,
MACFB_DRAW_LINE4,
MACFB_DRAW_LINE8,
MACFB_DRAW_LINE16,
MACFB_DRAW_LINE24,
MACFB_DRAW_LINE_NB,
};
static macfb_draw_line_func * const
macfb_draw_line_table[MACFB_DRAW_LINE_NB] = {
macfb_draw_line1,
macfb_draw_line2,
macfb_draw_line4,
macfb_draw_line8,
macfb_draw_line16,
macfb_draw_line24,
};
static int macfb_check_dirty(MacfbState *s, DirtyBitmapSnapshot *snap,
ram_addr_t addr, int len)
{
return memory_region_snapshot_get_dirty(&s->mem_vram, snap, addr, len);
}
static void macfb_draw_graphic(MacfbState *s)
{
DisplaySurface *surface = qemu_console_surface(s->con);
DirtyBitmapSnapshot *snap = NULL;
ram_addr_t page;
uint32_t v = 0;
int y, ymin;
int macfb_stride = (s->depth * s->width + 7) / 8;
macfb_draw_line_func *macfb_draw_line;
switch (s->depth) {
case 1:
v = MACFB_DRAW_LINE1;
break;
case 2:
v = MACFB_DRAW_LINE2;
break;
case 4:
v = MACFB_DRAW_LINE4;
break;
case 8:
v = MACFB_DRAW_LINE8;
break;
case 16:
v = MACFB_DRAW_LINE16;
break;
case 24:
v = MACFB_DRAW_LINE24;
break;
}
macfb_draw_line = macfb_draw_line_table[v];
assert(macfb_draw_line != NULL);
snap = memory_region_snapshot_and_clear_dirty(&s->mem_vram, 0x0,
memory_region_size(&s->mem_vram),
DIRTY_MEMORY_VGA);
ymin = -1;
page = 0;
for (y = 0; y < s->height; y++, page += macfb_stride) {
if (macfb_check_dirty(s, snap, page, macfb_stride)) {
uint8_t *data_display;
data_display = surface_data(surface) + y * surface_stride(surface);
macfb_draw_line(s, data_display, page, s->width);
if (ymin < 0) {
ymin = y;
}
} else {
if (ymin >= 0) {
dpy_gfx_update(s->con, 0, ymin, s->width, y - ymin);
ymin = -1;
}
}
}
if (ymin >= 0) {
dpy_gfx_update(s->con, 0, ymin, s->width, y - ymin);
}
g_free(snap);
}
static void macfb_invalidate_display(void *opaque)
{
MacfbState *s = opaque;
memory_region_set_dirty(&s->mem_vram, 0, MACFB_VRAM_SIZE);
}
static void macfb_update_display(void *opaque)
{
MacfbState *s = opaque;
DisplaySurface *surface = qemu_console_surface(s->con);
qemu_flush_coalesced_mmio_buffer();
if (s->width == 0 || s->height == 0) {
return;
}
if (s->width != surface_width(surface) ||
s->height != surface_height(surface)) {
qemu_console_resize(s->con, s->width, s->height);
}
macfb_draw_graphic(s);
}
static void macfb_reset(MacfbState *s)
{
int i;
s->palette_current = 0;
for (i = 0; i < 256; i++) {
s->color_palette[i * 3] = 255 - i;
s->color_palette[i * 3 + 1] = 255 - i;
s->color_palette[i * 3 + 2] = 255 - i;
}
memset(s->vram, 0, MACFB_VRAM_SIZE);
macfb_invalidate_display(s);
}
static uint64_t macfb_ctrl_read(void *opaque,
hwaddr addr,
unsigned int size)
{
return 0;
}
static void macfb_ctrl_write(void *opaque,
hwaddr addr,
uint64_t val,
unsigned int size)
{
MacfbState *s = opaque;
switch (addr) {
case DAFB_RESET:
s->palette_current = 0;
break;
case DAFB_LUT:
s->color_palette[s->palette_current++] = val;
if (s->palette_current % 3) {
macfb_invalidate_display(s);
}
break;
}
}
static const MemoryRegionOps macfb_ctrl_ops = {
.read = macfb_ctrl_read,
.write = macfb_ctrl_write,
.endianness = DEVICE_BIG_ENDIAN,
.impl.min_access_size = 1,
.impl.max_access_size = 4,
};
static int macfb_post_load(void *opaque, int version_id)
{
macfb_invalidate_display(opaque);
return 0;
}
static const VMStateDescription vmstate_macfb = {
.name = "macfb",
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.post_load = macfb_post_load,
.fields = (VMStateField[]) {
VMSTATE_UINT8_ARRAY(color_palette, MacfbState, 256 * 3),
VMSTATE_UINT32(palette_current, MacfbState),
VMSTATE_END_OF_LIST()
}
};
static const GraphicHwOps macfb_ops = {
.invalidate = macfb_invalidate_display,
.gfx_update = macfb_update_display,
};
static void macfb_common_realize(DeviceState *dev, MacfbState *s, Error **errp)
{
DisplaySurface *surface;
if (s->depth != 1 && s->depth != 2 && s->depth != 4 && s->depth != 8 &&
s->depth != 16 && s->depth != 24) {
error_setg(errp, "unknown guest depth %d", s->depth);
return;
}
s->con = graphic_console_init(dev, 0, &macfb_ops, s);
surface = qemu_console_surface(s->con);
if (surface_bits_per_pixel(surface) != 32) {
error_setg(errp, "unknown host depth %d",
surface_bits_per_pixel(surface));
return;
}
memory_region_init_io(&s->mem_ctrl, NULL, &macfb_ctrl_ops, s, "macfb-ctrl",
0x1000);
memory_region_init_ram_nomigrate(&s->mem_vram, OBJECT(s), "macfb-vram",
MACFB_VRAM_SIZE, errp);
s->vram = memory_region_get_ram_ptr(&s->mem_vram);
s->vram_bit_mask = MACFB_VRAM_SIZE - 1;
vmstate_register_ram(&s->mem_vram, dev);
memory_region_set_coalescing(&s->mem_vram);
}
static void macfb_sysbus_realize(DeviceState *dev, Error **errp)
{
MacfbSysBusState *s = MACFB(dev);
MacfbState *ms = &s->macfb;
macfb_common_realize(dev, ms, errp);
sysbus_init_mmio(SYS_BUS_DEVICE(s), &ms->mem_ctrl);
sysbus_init_mmio(SYS_BUS_DEVICE(s), &ms->mem_vram);
}
const uint8_t macfb_rom[] = {
255, 0, 0, 0,
};
static void macfb_nubus_realize(DeviceState *dev, Error **errp)
{
NubusDevice *nd = NUBUS_DEVICE(dev);
MacfbNubusState *s = NUBUS_MACFB(dev);
MacfbNubusDeviceClass *ndc = MACFB_NUBUS_GET_CLASS(dev);
MacfbState *ms = &s->macfb;
ndc->parent_realize(dev, errp);
macfb_common_realize(dev, ms, errp);
memory_region_add_subregion(&nd->slot_mem, DAFB_BASE, &ms->mem_ctrl);
memory_region_add_subregion(&nd->slot_mem, VIDEO_BASE, &ms->mem_vram);
nubus_register_rom(nd, macfb_rom, sizeof(macfb_rom), 1, 9, 0xf);
}
static void macfb_sysbus_reset(DeviceState *d)
{
MacfbSysBusState *s = MACFB(d);
macfb_reset(&s->macfb);
}
static void macfb_nubus_reset(DeviceState *d)
{
MacfbNubusState *s = NUBUS_MACFB(d);
macfb_reset(&s->macfb);
}
static Property macfb_sysbus_properties[] = {
DEFINE_PROP_UINT32("width", MacfbSysBusState, macfb.width, 640),
DEFINE_PROP_UINT32("height", MacfbSysBusState, macfb.height, 480),
DEFINE_PROP_UINT8("depth", MacfbSysBusState, macfb.depth, 8),
DEFINE_PROP_END_OF_LIST(),
};
static Property macfb_nubus_properties[] = {
DEFINE_PROP_UINT32("width", MacfbNubusState, macfb.width, 640),
DEFINE_PROP_UINT32("height", MacfbNubusState, macfb.height, 480),
DEFINE_PROP_UINT8("depth", MacfbNubusState, macfb.depth, 8),
DEFINE_PROP_END_OF_LIST(),
};
static void macfb_sysbus_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = macfb_sysbus_realize;
dc->desc = "SysBus Macintosh framebuffer";
dc->reset = macfb_sysbus_reset;
dc->vmsd = &vmstate_macfb;
dc->props = macfb_sysbus_properties;
}
static void macfb_nubus_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
MacfbNubusDeviceClass *ndc = MACFB_NUBUS_DEVICE_CLASS(klass);
device_class_set_parent_realize(dc, macfb_nubus_realize,
&ndc->parent_realize);
dc->desc = "Nubus Macintosh framebuffer";
dc->reset = macfb_nubus_reset;
dc->vmsd = &vmstate_macfb;
dc->props = macfb_nubus_properties;
}
static TypeInfo macfb_sysbus_info = {
.name = TYPE_MACFB,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(MacfbSysBusState),
.class_init = macfb_sysbus_class_init,
};
static TypeInfo macfb_nubus_info = {
.name = TYPE_NUBUS_MACFB,
.parent = TYPE_NUBUS_DEVICE,
.instance_size = sizeof(MacfbNubusState),
.class_init = macfb_nubus_class_init,
.class_size = sizeof(MacfbNubusDeviceClass),
};
static void macfb_register_types(void)
{
type_register_static(&macfb_sysbus_info);
type_register_static(&macfb_nubus_info);
}
type_init(macfb_register_types)

+ 10
- 0
hw/m68k/Kconfig View File

@ -12,3 +12,13 @@ config NEXTCUBE
bool
select FRAMEBUFFER
select ESCC
config Q800
bool
select MAC_VIA
select NUBUS
select MACFB
select SWIM
select ESCC
select ESP
select DP8393X

+ 1
- 0
hw/m68k/Makefile.objs View File

@ -1,3 +1,4 @@
obj-$(CONFIG_AN5206) += an5206.o mcf5206.o
obj-$(CONFIG_MCF5208) += mcf5208.o mcf_intc.o
obj-$(CONFIG_NEXTCUBE) += next-kbd.o next-cube.o
obj-$(CONFIG_Q800) += q800.o

+ 114
- 0
hw/m68k/bootinfo.h View File

@ -0,0 +1,114 @@
/*
* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
*
* Bootinfo tags from linux bootinfo.h and bootinfo-mac.h:
* This is an easily parsable and extendable structure containing all
* information to be passed from the bootstrap to the kernel
*
* This structure is copied right after the kernel by the bootstrap
* routine.
*/
#ifndef HW_M68K_BOOTINFO_H
#define HW_M68K_BOOTINFO_H
struct bi_record {
uint16_t tag; /* tag ID */
uint16_t size; /* size of record */
uint32_t data[0]; /* data */
};
/* machine independent tags */
#define BI_LAST 0x0000 /* last record */
#define BI_MACHTYPE 0x0001 /* machine type (u_long) */
#define BI_CPUTYPE 0x0002 /* cpu type (u_long) */
#define BI_FPUTYPE 0x0003 /* fpu type (u_long) */
#define BI_MMUTYPE 0x0004 /* mmu type (u_long) */
#define BI_MEMCHUNK 0x0005 /* memory chunk address and size */
/* (struct mem_info) */
#define BI_RAMDISK 0x0006 /* ramdisk address and size */
/* (struct mem_info) */
#define BI_COMMAND_LINE 0x0007 /* kernel command line parameters */
/* (string) */
/* Macintosh-specific tags (all u_long) */
#define BI_MAC_MODEL 0x8000 /* Mac Gestalt ID (model type) */
#define BI_MAC_VADDR 0x8001 /* Mac video base address */
#define BI_MAC_VDEPTH 0x8002 /* Mac video depth */
#define BI_MAC_VROW 0x8003 /* Mac video rowbytes */
#define BI_MAC_VDIM 0x8004 /* Mac video dimensions */
#define BI_MAC_VLOGICAL 0x8005 /* Mac video logical base */
#define BI_MAC_SCCBASE 0x8006 /* Mac SCC base address */
#define BI_MAC_BTIME 0x8007 /* Mac boot time */
#define BI_MAC_GMTBIAS 0x8008 /* Mac GMT timezone offset */
#define BI_MAC_MEMSIZE 0x8009 /* Mac RAM size (sanity check) */
#define BI_MAC_CPUID 0x800a /* Mac CPU type (sanity check) */
#define BI_MAC_ROMBASE 0x800b /* Mac system ROM base address */
/* Macintosh hardware profile data */
#define BI_MAC_VIA1BASE 0x8010 /* Mac VIA1 base address (always present) */
#define BI_MAC_VIA2BASE 0x8011 /* Mac VIA2 base address (type varies) */
#define BI_MAC_VIA2TYPE 0x8012 /* Mac VIA2 type (VIA, RBV, OSS) */
#define BI_MAC_ADBTYPE 0x8013 /* Mac ADB interface type */
#define BI_MAC_ASCBASE 0x8014 /* Mac Apple Sound Chip base address */
#define BI_MAC_SCSI5380 0x8015 /* Mac NCR 5380 SCSI (base address, multi) */
#define BI_MAC_SCSIDMA 0x8016 /* Mac SCSI DMA (base address) */
#define BI_MAC_SCSI5396 0x8017 /* Mac NCR 53C96 SCSI (base address, multi) */
#define BI_MAC_IDETYPE 0x8018 /* Mac IDE interface type */
#define BI_MAC_IDEBASE 0x8019 /* Mac IDE interface base address */
#define BI_MAC_NUBUS 0x801a /* Mac Nubus type (none, regular, pseudo) */
#define BI_MAC_SLOTMASK 0x801b /* Mac Nubus slots present */
#define BI_MAC_SCCTYPE 0x801c /* Mac SCC serial type (normal, IOP) */
#define BI_MAC_ETHTYPE 0x801d /* Mac builtin ethernet type (Sonic, MACE */
#define BI_MAC_ETHBASE 0x801e /* Mac builtin ethernet base address */
#define BI_MAC_PMU 0x801f /* Mac power management / poweroff hardware */
#define BI_MAC_IOP_SWIM 0x8020 /* Mac SWIM floppy IOP */
#define BI_MAC_IOP_ADB 0x8021 /* Mac ADB IOP */
#define BOOTINFO0(as, base, id) \
do { \
stw_phys(as, base, id); \
base += 2; \
stw_phys(as, base, sizeof(struct bi_record)); \
base += 2; \
} while (0)
#define BOOTINFO1(as, base, id, value) \
do { \
stw_phys(as, base, id); \
base += 2; \
stw_phys(as, base, sizeof(struct bi_record) + 4); \
base += 2; \
stl_phys(as, base, value); \
base += 4; \
} while (0)
#define BOOTINFO2(as, base, id, value1, value2) \
do { \
stw_phys(as, base, id); \
base += 2; \
stw_phys(as, base, sizeof(struct bi_record) + 8); \
base += 2; \
stl_phys(as, base, value1); \
base += 4; \
stl_phys(as, base, value2); \
base += 4; \
} while (0)
#define BOOTINFOSTR(as, base, id, string) \
do { \
int i; \
stw_phys(as, base, id); \
base += 2; \
stw_phys(as, base, \
(sizeof(struct bi_record) + strlen(string) + 2) & ~1); \
base += 2; \
for (i = 0; string[i]; i++) { \
stb_phys(as, base++, string[i]); \
} \
stb_phys(as, base++, 0); \
base = (parameters_base + 1) & ~1; \
} while (0)
#endif

+ 401
- 0
hw/m68k/q800.c View File

@ -0,0 +1,401 @@
/*
* QEMU Motorla 680x0 Macintosh hardware System Emulator
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "qemu-common.h"
#include "sysemu/sysemu.h"
#include "cpu.h"
#include "hw/hw.h"
#include "hw/boards.h"
#include "hw/irq.h"
#include "elf.h"
#include "hw/loader.h"
#include "ui/console.h"
#include "exec/address-spaces.h"
#include "hw/char/escc.h"
#include "hw/sysbus.h"
#include "hw/scsi/esp.h"
#include "bootinfo.h"
#include "hw/misc/mac_via.h"
#include "hw/input/adb.h"
#include "hw/nubus/mac-nubus-bridge.h"
#include "hw/display/macfb.h"
#include "hw/block/swim.h"
#include "net/net.h"
#include "qapi/error.h"
#include "sysemu/qtest.h"
#include "sysemu/runstate.h"
#include "sysemu/reset.h"
#define MACROM_ADDR 0x40000000
#define MACROM_SIZE 0x00100000
#define MACROM_FILENAME "MacROM.bin"
#define Q800_MACHINE_ID 35
#define Q800_CPU_ID (1 << 2)
#define Q800_FPU_ID (1 << 2)
#define Q800_MMU_ID (1 << 2)
#define MACH_MAC 3
#define Q800_MAC_CPU_ID 2
#define VIA_BASE 0x50f00000
#define SONIC_PROM_BASE 0x50f08000
#define SONIC_BASE 0x50f0a000
#define SCC_BASE 0x50f0c020
#define ESP_BASE 0x50f10000
#define ESP_PDMA 0x50f10100
#define ASC_BASE 0x50F14000
#define SWIM_BASE 0x50F1E000
#define NUBUS_SUPER_SLOT_BASE 0x60000000
#define NUBUS_SLOT_BASE 0xf0000000
/*
* the video base, whereas it a Nubus address,
* is needed by the kernel to have early display and
* thus provided by the bootloader
*/
#define VIDEO_BASE 0xf9001000
#define MAC_CLOCK 3686418
/*
* The GLUE (General Logic Unit) is an Apple custom integrated circuit chip
* that performs a variety of functions (RAM management, clock generation, ...).
* The GLUE chip receives interrupt requests from various devices,
* assign priority to each, and asserts one or more interrupt line to the
* CPU.
*/
typedef struct {
M68kCPU *cpu;
uint8_t ipr;
} GLUEState;
static void GLUE_set_irq(void *opaque, int irq, int level)
{
GLUEState *s = opaque;
int i;
if (level) {
s->ipr |= 1 << irq;
} else {
s->ipr &= ~(1 << irq);
}
for (i = 7; i >= 0; i--) {
if ((s->ipr >> i) & 1) {
m68k_set_irq_level(s->cpu, i + 1, i + 25);
return;
}
}
m68k_set_irq_level(s->cpu, 0, 0);
}
static void main_cpu_reset(void *opaque)
{
M68kCPU *cpu = opaque;
CPUState *cs = CPU(cpu);
cpu_reset(cs);
cpu->env.aregs[7] = ldl_phys(cs->as, 0);
cpu->env.pc = ldl_phys(cs->as, 4);
}
static void q800_init(MachineState *machine)
{
M68kCPU *cpu = NULL;
int linux_boot;
int32_t kernel_size;
uint64_t elf_entry;
char *filename;
int bios_size;
ram_addr_t initrd_base;
int32_t initrd_size;
MemoryRegion *rom;
MemoryRegion *ram;
ram_addr_t ram_size = machine->ram_size;
const char *kernel_filename = machine->kernel_filename;
const char *initrd_filename = machine->initrd_filename;
const char *kernel_cmdline = machine->kernel_cmdline;
hwaddr parameters_base;
CPUState *cs;
DeviceState *dev;
DeviceState *via_dev;
SysBusESPState *sysbus_esp;
ESPState *esp;
SysBusDevice *sysbus;
BusState *adb_bus;
NubusBus *nubus;
GLUEState *irq;
qemu_irq *pic;
linux_boot = (kernel_filename != NULL);
if (ram_size > 1 * GiB) {
error_report("Too much memory for this machine: %" PRId64 " MiB, "
"maximum 1024 MiB", ram_size / MiB);
exit(1);
}
/* init CPUs */
cpu = M68K_CPU(cpu_create(machine->cpu_type));
qemu_register_reset(main_cpu_reset, cpu);
ram = g_malloc(sizeof(*ram));
memory_region_init_ram(ram, NULL, "m68k_mac.ram", ram_size, &error_abort);
memory_region_add_subregion(get_system_memory(), 0, ram);
/* IRQ Glue */
irq = g_new0(GLUEState, 1);
irq->cpu = cpu;
pic = qemu_allocate_irqs(GLUE_set_irq, irq, 8);
/* VIA */
via_dev = qdev_create(NULL, TYPE_MAC_VIA);
qdev_init_nofail(via_dev);
sysbus = SYS_BUS_DEVICE(via_dev);
sysbus_mmio_map(sysbus, 0, VIA_BASE);
qdev_connect_gpio_out_named(DEVICE(sysbus), "irq", 0, pic[0]);
qdev_connect_gpio_out_named(DEVICE(sysbus), "irq", 1, pic[1]);
adb_bus = qdev_get_child_bus(via_dev, "adb.0");
dev = qdev_create(adb_bus, TYPE_ADB_KEYBOARD);
qdev_init_nofail(dev);
dev = qdev_create(adb_bus, TYPE_ADB_MOUSE);
qdev_init_nofail(dev);
/* MACSONIC */
if (nb_nics > 1) {
error_report("q800 can only have one ethernet interface");
exit(1);
}
qemu_check_nic_model(&nd_table[0], "dp83932");
/*
* MacSonic driver needs an Apple MAC address
* Valid prefix are:
* 00:05:02 Apple
* 00:80:19 Dayna Communications, Inc.
* 00:A0:40 Apple
* 08:00:07 Apple
* (Q800 use the last one)
*/
nd_table[0].macaddr.a[0] = 0x08;
nd_table[0].macaddr.a[1] = 0x00;
nd_table[0].macaddr.a[2] = 0x07;
dev = qdev_create(NULL, "dp8393x");
qdev_set_nic_properties(dev, &nd_table[0]);
qdev_prop_set_uint8(dev, "it_shift", 2);
qdev_prop_set_bit(dev, "big_endian", true);
qdev_prop_set_ptr(dev, "dma_mr", get_system_memory());
qdev_init_nofail(dev);
sysbus = SYS_BUS_DEVICE(dev);
sysbus_mmio_map(sysbus, 0, SONIC_BASE);
sysbus_mmio_map(sysbus, 1, SONIC_PROM_BASE);
sysbus_connect_irq(sysbus, 0, pic[2]);
/* SCC */
dev = qdev_create(NULL, TYPE_ESCC);
qdev_prop_set_uint32(dev, "disabled", 0);
qdev_prop_set_uint32(dev, "frequency", MAC_CLOCK);
qdev_prop_set_uint32(dev, "it_shift", 1);
qdev_prop_set_bit(dev, "bit_swap", true);
qdev_prop_set_chr(dev, "chrA", serial_hd(0));
qdev_prop_set_chr(dev, "chrB", serial_hd(1));
qdev_prop_set_uint32(dev, "chnBtype", 0);
qdev_prop_set_uint32(dev, "chnAtype", 0);
qdev_init_nofail(dev);
sysbus = SYS_BUS_DEVICE(dev);
sysbus_connect_irq(sysbus, 0, pic[3]);
sysbus_connect_irq(sysbus, 1, pic[3]);
sysbus_mmio_map(sysbus, 0, SCC_BASE);
/* SCSI */
dev = qdev_create(NULL, TYPE_ESP);
sysbus_esp = ESP_STATE(dev);
esp = &sysbus_esp->esp;
esp->dma_memory_read = NULL;
esp->dma_memory_write = NULL;
esp->dma_opaque = NULL;
sysbus_esp->it_shift = 4;
esp->dma_enabled = 1;
qdev_init_nofail(dev);
sysbus = SYS_BUS_DEVICE(dev);
sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in_named(via_dev,
"via2-irq",
VIA2_IRQ_SCSI_BIT));
sysbus_connect_irq(sysbus, 1,
qdev_get_gpio_in_named(via_dev, "via2-irq",
VIA2_IRQ_SCSI_DATA_BIT));
sysbus_mmio_map(sysbus, 0, ESP_BASE);
sysbus_mmio_map(sysbus, 1, ESP_PDMA);
scsi_bus_legacy_handle_cmdline(&esp->bus);
/* SWIM floppy controller */
dev = qdev_create(NULL, TYPE_SWIM);
qdev_init_nofail(dev);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, SWIM_BASE);
/* NuBus */
dev = qdev_create(NULL, TYPE_MAC_NUBUS_BRIDGE);
qdev_init_nofail(dev);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, NUBUS_SUPER_SLOT_BASE);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, NUBUS_SLOT_BASE);
nubus = MAC_NUBUS_BRIDGE(dev)->bus;
/* framebuffer in nubus slot #9 */
dev = qdev_create(BUS(nubus), TYPE_NUBUS_MACFB);
qdev_prop_set_uint32(dev, "width", graphic_width);
qdev_prop_set_uint32(dev, "height", graphic_height);
qdev_prop_set_uint8(dev, "depth", graphic_depth);
qdev_init_nofail(dev);
cs = CPU(cpu);
if (linux_boot) {
uint64_t high;
kernel_size = load_elf(kernel_filename, NULL, NULL, NULL,
&elf_entry, NULL, &high, 1,
EM_68K, 0, 0);
if (kernel_size < 0) {
error_report("could not load kernel '%s'", kernel_filename);
exit(1);
}
stl_phys(cs->as, 4, elf_entry); /* reset initial PC */
parameters_base = (high + 1) & ~1;
BOOTINFO1(cs->as, parameters_base, BI_MACHTYPE, MACH_MAC);
BOOTINFO1(cs->as, parameters_base, BI_FPUTYPE, Q800_FPU_ID);
BOOTINFO1(cs->as, parameters_base, BI_MMUTYPE, Q800_MMU_ID);
BOOTINFO1(cs->as, parameters_base, BI_CPUTYPE, Q800_CPU_ID);
BOOTINFO1(cs->as, parameters_base, BI_MAC_CPUID, Q800_MAC_CPU_ID);
BOOTINFO1(cs->as, parameters_base, BI_MAC_MODEL, Q800_MACHINE_ID);
BOOTINFO1(cs->as, parameters_base,
BI_MAC_MEMSIZE, ram_size >> 20); /* in MB */
BOOTINFO2(cs->as, parameters_base, BI_MEMCHUNK, 0, ram_size);
BOOTINFO1(cs->as, parameters_base, BI_MAC_VADDR, VIDEO_BASE);
BOOTINFO1(cs->as, parameters_base, BI_MAC_VDEPTH, graphic_depth);
BOOTINFO1(cs->as, parameters_base, BI_MAC_VDIM,
(graphic_height << 16) | graphic_width);
BOOTINFO1(cs->as, parameters_base, BI_MAC_VROW,
(graphic_width * graphic_depth + 7) / 8);
BOOTINFO1(cs->as, parameters_base, BI_MAC_SCCBASE, SCC_BASE);
if (kernel_cmdline) {
BOOTINFOSTR(cs->as, parameters_base, BI_COMMAND_LINE,
kernel_cmdline);
}
/* load initrd */
if (initrd_filename) {
initrd_size = get_image_size(initrd_filename);
if (initrd_size < 0) {
error_report("could not load initial ram disk '%s'",
initrd_filename);
exit(1);
}
initrd_base = (ram_size - initrd_size) & TARGET_PAGE_MASK;
load_image_targphys(initrd_filename, initrd_base,
ram_size - initrd_base);
BOOTINFO2(cs->as, parameters_base, BI_RAMDISK, initrd_base,
initrd_size);
} else {
initrd_base = 0;
initrd_size = 0;
}
BOOTINFO0(cs->as, parameters_base, BI_LAST);
} else {
uint8_t *ptr;
/* allocate and load BIOS */
rom = g_malloc(sizeof(*rom));
memory_region_init_ram(rom, NULL, "m68k_mac.rom", MACROM_SIZE,
&error_abort);
if (bios_name == NULL) {
bios_name = MACROM_FILENAME;
}
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
memory_region_set_readonly(rom, true);
memory_region_add_subregion(get_system_memory(), MACROM_ADDR, rom);
/* Load MacROM binary */
if (filename) {
bios_size = load_image_targphys(filename, MACROM_ADDR, MACROM_SIZE);
g_free(filename);
} else {
bios_size = -1;
}
/* Remove qtest_enabled() check once firmware files are in the tree */
if (!qtest_enabled()) {
if (bios_size < 0 || bios_size > MACROM_SIZE) {
error_report("could not load MacROM '%s'", bios_name);
exit(1);
}
ptr = rom_ptr(MACROM_ADDR, MACROM_SIZE);
stl_phys(cs->as, 0, ldl_p(ptr)); /* reset initial SP */
stl_phys(cs->as, 4,
MACROM_ADDR + ldl_p(ptr + 4)); /* reset initial PC */
}
}
}
static void q800_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
mc->desc = "Macintosh Quadra 800";
mc->init = q800_init;
mc->default_cpu_type = M68K_CPU_TYPE_NAME("m68040");
mc->max_cpus = 1;
mc->is_default = 0;
mc->block_default_type = IF_SCSI;
}
static const TypeInfo q800_machine_typeinfo = {
.name = MACHINE_TYPE_NAME("q800"),
.parent = TYPE_MACHINE,
.class_init = q800_machine_class_init,
};
static void q800_machine_register_types(void)
{
type_register_static(&q800_machine_typeinfo);
}
type_init(q800_machine_register_types)

+ 5
- 0
hw/misc/Kconfig View File

@ -120,4 +120,9 @@ config AUX
config UNIMP
bool
config MAC_VIA
bool
select MOS6522
select ADB
source macio/Kconfig

+ 1
- 0
hw/misc/Makefile.objs View File

@ -79,5 +79,6 @@ common-obj-$(CONFIG_ASPEED_SOC) += aspeed_xdma.o
common-obj-$(CONFIG_ASPEED_SOC) += aspeed_scu.o aspeed_sdmc.o