m68k pull request 20210315

Add m68k virt machine
 -----BEGIN PGP SIGNATURE-----
 
 iQJGBAABCAAwFiEEzS913cjjpNwuT1Fz8ww4vT8vvjwFAmBPxo8SHGxhdXJlbnRA
 dml2aWVyLmV1AAoJEPMMOL0/L748LnYQAKX0IV5AzSU04fq1o6AA5MfgVjsF3v0/
 FdvudfqSl6QjBfE6uqM2YjvgNRNPkSYPoTmoE476l0WcFwCH42lBDs7vt7oqSMtW
 lSc2aXUM6MEUfkPCZ5WLUjAT7R4+pT2C9f0kPnEs2eepr4/ho9rXsfPpKkag5GLs
 MvzHOK2ecHh0HDNPekG74yEbrn4k0yl3miyUimIG5Fk2NUP7dJ5J+ue+5IDHrFOu
 ZU/0wXb01rJjp1xEZSv/9RqINvLA+xzlK0NExEGeYCwnhQi7aRCw+peTIuCW2RCy
 +Y3TEyPrWpplVGuJjgpFS9ZTx9Qd4tOrGe9+QfurYCWlq6yp9QCRuX0Ee5As8471
 jLW6wjiMGE3cK5uiZxx0sqplTI5SBuYIznXf/wruTHOajGuNsMFN4HfzJYtCTCOt
 aytd3Xibm+OxojJ5xasjva7U4l8ojEdeSxbq8r5FiFc5ezCNhLQzAANQZHaHNXY+
 9pQteKVJq05DdBz5LZ18wInINdFWbS68UANmVR9FEdqpDWmOiKD7cF8U3U7ikVz5
 AcfcqfY2At3FUSmmy6Wy0BRkgBiRjSU9q5QnqIMjkzcZ6aONLA11cziR5PHZD5ZO
 LqTXEngrwo/c/jNLDfsJhCCC7Lwpx5DUSzl5XnqWdLpVt5fF9GX0j9UxWC8ZCBNC
 SZXvG3oDSSBB
 =1YJ9
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/vivier/tags/m68k-for-6.0-pull-request' into staging

m68k pull request 20210315

Add m68k virt machine

# gpg: Signature made Mon 15 Mar 2021 20:41:51 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/m68k-for-6.0-pull-request:
  m68k: add Virtual M68k Machine
  m68k: add a system controller
  m68k: add an interrupt controller
  hw/intc: add goldfish-pic
  hw/char: add goldfish-tty

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2021-03-17 10:38:27 +00:00
commit ff81439aaf
24 changed files with 1330 additions and 0 deletions

View File

@ -1130,6 +1130,19 @@ F: include/hw/nubus/*
F: include/hw/display/macfb.h
F: include/hw/block/swim.h
virt
M: Laurent Vivier <laurent@vivier.eu>
S: Maintained
F: hw/m68k/virt.c
F: hw/char/goldfish_tty.c
F: hw/intc/goldfish_pic.c
F: hw/intc/m68k_irqc.c
F: hw/misc/virt_ctrl.c
F: include/hw/char/goldfish_tty.h
F: include/hw/intc/goldfish_pic.h
F: include/hw/intc/m68k_irqc.h
F: include/hw/misc/virt_ctrl.h
MicroBlaze Machines
-------------------
petalogix_s3adsp1800

View File

@ -8,3 +8,4 @@ CONFIG_AN5206=y
CONFIG_MCF5208=y
CONFIG_NEXTCUBE=y
CONFIG_Q800=y
CONFIG_M68K_VIRT=y

26
docs/specs/virt-ctlr.txt Normal file
View File

@ -0,0 +1,26 @@
Virtual System Controller
=========================
This device is a simple interface defined for the pure virtual machine with no
hardware reference implementation to allow the guest kernel to send command
to the host hypervisor.
The specification can evolve, the current state is defined as below.
This is a MMIO mapped device using 256 bytes.
Two 32bit registers are defined:
1- the features register (read-only, address 0x00)
This register allows the device to report features supported by the
controller.
The only feature supported for the moment is power control (0x01).
2- the command register (write-only, address 0x04)
This register allows the kernel to send the commands to the hypervisor.
The implemented commands are part of the power control feature and
are reset (1), halt (2) and panic (3).
A basic command, no-op (0), is always present and can be used to test the
register access. This command has no effect.

View File

@ -64,3 +64,6 @@ config MCHP_PFSOC_MMUART
config SIFIVE_UART
bool
config GOLDFISH_TTY
bool

285
hw/char/goldfish_tty.c Normal file
View File

@ -0,0 +1,285 @@
/*
* SPDX-License-Identifer: GPL-2.0-or-later
*
* Goldfish TTY
*
* (c) 2020 Laurent Vivier <laurent@vivier.eu>
*
*/
#include "qemu/osdep.h"
#include "hw/irq.h"
#include "hw/qdev-properties-system.h"
#include "hw/sysbus.h"
#include "migration/vmstate.h"
#include "chardev/char-fe.h"
#include "qemu/log.h"
#include "trace.h"
#include "exec/address-spaces.h"
#include "hw/char/goldfish_tty.h"
#define GOLDFISH_TTY_VERSION 1
/* registers */
enum {
REG_PUT_CHAR = 0x00,
REG_BYTES_READY = 0x04,
REG_CMD = 0x08,
REG_DATA_PTR = 0x10,
REG_DATA_LEN = 0x14,
REG_DATA_PTR_HIGH = 0x18,
REG_VERSION = 0x20,
};
/* commands */
enum {
CMD_INT_DISABLE = 0x00,
CMD_INT_ENABLE = 0x01,
CMD_WRITE_BUFFER = 0x02,
CMD_READ_BUFFER = 0x03,
};
static uint64_t goldfish_tty_read(void *opaque, hwaddr addr,
unsigned size)
{
GoldfishTTYState *s = opaque;
uint64_t value = 0;
switch (addr) {
case REG_BYTES_READY:
value = fifo8_num_used(&s->rx_fifo);
break;
case REG_VERSION:
value = GOLDFISH_TTY_VERSION;
break;
default:
qemu_log_mask(LOG_UNIMP,
"%s: unimplemented register read 0x%02"HWADDR_PRIx"\n",
__func__, addr);
break;
}
trace_goldfish_tty_read(s, addr, size, value);
return value;
}
static void goldfish_tty_cmd(GoldfishTTYState *s, uint32_t cmd)
{
uint32_t to_copy;
uint8_t *buf;
uint8_t data_out[GOLFISH_TTY_BUFFER_SIZE];
int len;
uint64_t ptr;
switch (cmd) {
case CMD_INT_DISABLE:
if (s->int_enabled) {
if (!fifo8_is_empty(&s->rx_fifo)) {
qemu_set_irq(s->irq, 0);
}
s->int_enabled = false;
}
break;
case CMD_INT_ENABLE:
if (!s->int_enabled) {
if (!fifo8_is_empty(&s->rx_fifo)) {
qemu_set_irq(s->irq, 1);
}
s->int_enabled = true;
}
break;
case CMD_WRITE_BUFFER:
len = s->data_len;
ptr = s->data_ptr;
while (len) {
to_copy = MIN(GOLFISH_TTY_BUFFER_SIZE, len);
address_space_rw(&address_space_memory, ptr,
MEMTXATTRS_UNSPECIFIED, data_out, to_copy, 0);
qemu_chr_fe_write_all(&s->chr, data_out, to_copy);
len -= to_copy;
ptr += to_copy;
}
break;
case CMD_READ_BUFFER:
len = s->data_len;
ptr = s->data_ptr;
while (len && !fifo8_is_empty(&s->rx_fifo)) {
buf = (uint8_t *)fifo8_pop_buf(&s->rx_fifo, len, &to_copy);
address_space_rw(&address_space_memory, ptr,
MEMTXATTRS_UNSPECIFIED, buf, to_copy, 1);
len -= to_copy;
ptr += to_copy;
}
if (s->int_enabled && fifo8_is_empty(&s->rx_fifo)) {
qemu_set_irq(s->irq, 0);
}
break;
}
}
static void goldfish_tty_write(void *opaque, hwaddr addr,
uint64_t value, unsigned size)
{
GoldfishTTYState *s = opaque;
unsigned char c;
trace_goldfish_tty_write(s, addr, size, value);
switch (addr) {
case REG_PUT_CHAR:
c = value;
qemu_chr_fe_write_all(&s->chr, &c, sizeof(c));
break;
case REG_CMD:
goldfish_tty_cmd(s, value);
break;
case REG_DATA_PTR:
s->data_ptr = value;
break;
case REG_DATA_PTR_HIGH:
s->data_ptr = deposit64(s->data_ptr, 32, 32, value);
break;
case REG_DATA_LEN:
s->data_len = value;
break;
default:
qemu_log_mask(LOG_UNIMP,
"%s: unimplemented register write 0x%02"HWADDR_PRIx"\n",
__func__, addr);
break;
}
}
static const MemoryRegionOps goldfish_tty_ops = {
.read = goldfish_tty_read,
.write = goldfish_tty_write,
.endianness = DEVICE_NATIVE_ENDIAN,
.valid.max_access_size = 4,
.impl.max_access_size = 4,
.impl.min_access_size = 4,
};
static int goldfish_tty_can_receive(void *opaque)
{
GoldfishTTYState *s = opaque;
int available = fifo8_num_free(&s->rx_fifo);
trace_goldfish_tty_can_receive(s, available);
return available;
}
static void goldfish_tty_receive(void *opaque, const uint8_t *buffer, int size)
{
GoldfishTTYState *s = opaque;
trace_goldfish_tty_receive(s, size);
g_assert(size <= fifo8_num_free(&s->rx_fifo));
fifo8_push_all(&s->rx_fifo, buffer, size);
if (s->int_enabled && !fifo8_is_empty(&s->rx_fifo)) {
qemu_set_irq(s->irq, 1);
}
}
static void goldfish_tty_reset(DeviceState *dev)
{
GoldfishTTYState *s = GOLDFISH_TTY(dev);
trace_goldfish_tty_reset(s);
fifo8_reset(&s->rx_fifo);
s->int_enabled = false;
s->data_ptr = 0;
s->data_len = 0;
}
static void goldfish_tty_realize(DeviceState *dev, Error **errp)
{
GoldfishTTYState *s = GOLDFISH_TTY(dev);
trace_goldfish_tty_realize(s);
fifo8_create(&s->rx_fifo, GOLFISH_TTY_BUFFER_SIZE);
memory_region_init_io(&s->iomem, OBJECT(s), &goldfish_tty_ops, s,
"goldfish_tty", 0x24);
if (qemu_chr_fe_backend_connected(&s->chr)) {
qemu_chr_fe_set_handlers(&s->chr, goldfish_tty_can_receive,
goldfish_tty_receive, NULL, NULL,
s, NULL, true);
}
}
static void goldfish_tty_unrealize(DeviceState *dev)
{
GoldfishTTYState *s = GOLDFISH_TTY(dev);
trace_goldfish_tty_unrealize(s);
fifo8_destroy(&s->rx_fifo);
}
static const VMStateDescription vmstate_goldfish_tty = {
.name = "goldfish_tty",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32(data_len, GoldfishTTYState),
VMSTATE_UINT64(data_ptr, GoldfishTTYState),
VMSTATE_BOOL(int_enabled, GoldfishTTYState),
VMSTATE_FIFO8(rx_fifo, GoldfishTTYState),
VMSTATE_END_OF_LIST()
}
};
static Property goldfish_tty_properties[] = {
DEFINE_PROP_CHR("chardev", GoldfishTTYState, chr),
DEFINE_PROP_END_OF_LIST(),
};
static void goldfish_tty_instance_init(Object *obj)
{
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
GoldfishTTYState *s = GOLDFISH_TTY(obj);
trace_goldfish_tty_instance_init(s);
sysbus_init_mmio(dev, &s->iomem);
sysbus_init_irq(dev, &s->irq);
}
static void goldfish_tty_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
device_class_set_props(dc, goldfish_tty_properties);
dc->reset = goldfish_tty_reset;
dc->realize = goldfish_tty_realize;
dc->unrealize = goldfish_tty_unrealize;
dc->vmsd = &vmstate_goldfish_tty;
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
}
static const TypeInfo goldfish_tty_info = {
.name = TYPE_GOLDFISH_TTY,
.parent = TYPE_SYS_BUS_DEVICE,
.class_init = goldfish_tty_class_init,
.instance_init = goldfish_tty_instance_init,
.instance_size = sizeof(GoldfishTTYState),
};
static void goldfish_tty_register_types(void)
{
type_register_static(&goldfish_tty_info);
}
type_init(goldfish_tty_register_types)

View File

@ -39,3 +39,5 @@ specific_ss.add(when: 'CONFIG_HTIF', if_true: files('riscv_htif.c'))
specific_ss.add(when: 'CONFIG_TERMINAL3270', if_true: files('terminal3270.c'))
specific_ss.add(when: 'CONFIG_VIRTIO', if_true: files('virtio-serial-bus.c'))
specific_ss.add(when: 'CONFIG_PSERIES', if_true: files('spapr_vty.c'))
specific_ss.add(when: 'CONFIG_GOLDFISH_TTY', if_true: files('goldfish_tty.c'))

View File

@ -20,6 +20,16 @@ virtio_console_flush_buf(unsigned int port, size_t len, ssize_t ret) "port %u, i
virtio_console_chr_read(unsigned int port, int size) "port %u, size %d"
virtio_console_chr_event(unsigned int port, int event) "port %u, event %d"
# goldfish_tty.c
goldfish_tty_read(void *dev, unsigned int addr, unsigned int size, uint64_t value) "tty: %p reg: 0x%02x size: %d value: 0x%"PRIx64
goldfish_tty_write(void *dev, unsigned int addr, unsigned int size, uint64_t value) "tty: %p reg: 0x%02x size: %d value: 0x%"PRIx64
goldfish_tty_can_receive(void *dev, unsigned int available) "tty: %p available: %u"
goldfish_tty_receive(void *dev, unsigned int size) "tty: %p size: %u"
goldfish_tty_reset(void *dev) "tty: %p"
goldfish_tty_realize(void *dev) "tty: %p"
goldfish_tty_unrealize(void *dev) "tty: %p"
goldfish_tty_instance_init(void *dev) "tty: %p"
# grlib_apbuart.c
grlib_apbuart_event(int event) "event:%d"
grlib_apbuart_writel_unknown(uint64_t addr, uint32_t value) "addr 0x%"PRIx64" value 0x%x"

View File

@ -67,3 +67,9 @@ config SIFIVE_CLINT
config SIFIVE_PLIC
bool
config GOLDFISH_PIC
bool
config M68K_IRQC
bool

219
hw/intc/goldfish_pic.c Normal file
View File

@ -0,0 +1,219 @@
/*
* SPDX-License-Identifer: GPL-2.0-or-later
*
* Goldfish PIC
*
* (c) 2020 Laurent Vivier <laurent@vivier.eu>
*
*/
#include "qemu/osdep.h"
#include "hw/irq.h"
#include "hw/qdev-properties.h"
#include "hw/sysbus.h"
#include "migration/vmstate.h"
#include "monitor/monitor.h"
#include "qemu/log.h"
#include "trace.h"
#include "hw/intc/intc.h"
#include "hw/intc/goldfish_pic.h"
/* registers */
enum {
REG_STATUS = 0x00,
REG_IRQ_PENDING = 0x04,
REG_IRQ_DISABLE_ALL = 0x08,
REG_DISABLE = 0x0c,
REG_ENABLE = 0x10,
};
static bool goldfish_pic_get_statistics(InterruptStatsProvider *obj,
uint64_t **irq_counts,
unsigned int *nb_irqs)
{
GoldfishPICState *s = GOLDFISH_PIC(obj);
*irq_counts = s->stats_irq_count;
*nb_irqs = ARRAY_SIZE(s->stats_irq_count);
return true;
}
static void goldfish_pic_print_info(InterruptStatsProvider *obj, Monitor *mon)
{
GoldfishPICState *s = GOLDFISH_PIC(obj);
monitor_printf(mon, "goldfish-pic.%d: pending=0x%08x enabled=0x%08x\n",
s->idx, s->pending, s->enabled);
}
static void goldfish_pic_update(GoldfishPICState *s)
{
if (s->pending & s->enabled) {
qemu_irq_raise(s->irq);
} else {
qemu_irq_lower(s->irq);
}
}
static void goldfish_irq_request(void *opaque, int irq, int level)
{
GoldfishPICState *s = opaque;
trace_goldfish_irq_request(s, s->idx, irq, level);
if (level) {
s->pending |= 1 << irq;
s->stats_irq_count[irq]++;
} else {
s->pending &= ~(1 << irq);
}
goldfish_pic_update(s);
}
static uint64_t goldfish_pic_read(void *opaque, hwaddr addr,
unsigned size)
{
GoldfishPICState *s = opaque;
uint64_t value = 0;
switch (addr) {
case REG_STATUS:
/* The number of pending interrupts (0 to 32) */
value = ctpop32(s->pending & s->enabled);
break;
case REG_IRQ_PENDING:
/* The pending interrupt mask */
value = s->pending & s->enabled;
break;
default:
qemu_log_mask(LOG_UNIMP,
"%s: unimplemented register read 0x%02"HWADDR_PRIx"\n",
__func__, addr);
break;
}
trace_goldfish_pic_read(s, s->idx, addr, size, value);
return value;
}
static void goldfish_pic_write(void *opaque, hwaddr addr,
uint64_t value, unsigned size)
{
GoldfishPICState *s = opaque;
trace_goldfish_pic_write(s, s->idx, addr, size, value);
switch (addr) {
case REG_IRQ_DISABLE_ALL:
s->enabled = 0;
s->pending = 0;
break;
case REG_DISABLE:
s->enabled &= ~value;
break;
case REG_ENABLE:
s->enabled |= value;
break;
default:
qemu_log_mask(LOG_UNIMP,
"%s: unimplemented register write 0x%02"HWADDR_PRIx"\n",
__func__, addr);
break;
}
goldfish_pic_update(s);
}
static const MemoryRegionOps goldfish_pic_ops = {
.read = goldfish_pic_read,
.write = goldfish_pic_write,
.endianness = DEVICE_NATIVE_ENDIAN,
.valid.max_access_size = 4,
.impl.min_access_size = 4,
.impl.max_access_size = 4,
};
static void goldfish_pic_reset(DeviceState *dev)
{
GoldfishPICState *s = GOLDFISH_PIC(dev);
int i;
trace_goldfish_pic_reset(s, s->idx);
s->pending = 0;
s->enabled = 0;
for (i = 0; i < ARRAY_SIZE(s->stats_irq_count); i++) {
s->stats_irq_count[i] = 0;
}
}
static void goldfish_pic_realize(DeviceState *dev, Error **errp)
{
GoldfishPICState *s = GOLDFISH_PIC(dev);
trace_goldfish_pic_realize(s, s->idx);
memory_region_init_io(&s->iomem, OBJECT(s), &goldfish_pic_ops, s,
"goldfish_pic", 0x24);
}
static const VMStateDescription vmstate_goldfish_pic = {
.name = "goldfish_pic",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32(pending, GoldfishPICState),
VMSTATE_UINT32(enabled, GoldfishPICState),
VMSTATE_END_OF_LIST()
}
};
static void goldfish_pic_instance_init(Object *obj)
{
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
GoldfishPICState *s = GOLDFISH_PIC(obj);
trace_goldfish_pic_instance_init(s);
sysbus_init_mmio(dev, &s->iomem);
sysbus_init_irq(dev, &s->irq);
qdev_init_gpio_in(DEVICE(obj), goldfish_irq_request, GOLDFISH_PIC_IRQ_NB);
}
static Property goldfish_pic_properties[] = {
DEFINE_PROP_UINT8("index", GoldfishPICState, idx, 0),
DEFINE_PROP_END_OF_LIST(),
};
static void goldfish_pic_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(oc);
dc->reset = goldfish_pic_reset;
dc->realize = goldfish_pic_realize;
dc->vmsd = &vmstate_goldfish_pic;
ic->get_statistics = goldfish_pic_get_statistics;
ic->print_info = goldfish_pic_print_info;
device_class_set_props(dc, goldfish_pic_properties);
}
static const TypeInfo goldfish_pic_info = {
.name = TYPE_GOLDFISH_PIC,
.parent = TYPE_SYS_BUS_DEVICE,
.class_init = goldfish_pic_class_init,
.instance_init = goldfish_pic_instance_init,
.instance_size = sizeof(GoldfishPICState),
.interfaces = (InterfaceInfo[]) {
{ TYPE_INTERRUPT_STATS_PROVIDER },
{ }
},
};
static void goldfish_pic_register_types(void)
{
type_register_static(&goldfish_pic_info);
}
type_init(goldfish_pic_register_types)

119
hw/intc/m68k_irqc.c Normal file
View File

@ -0,0 +1,119 @@
/*
* SPDX-License-Identifer: GPL-2.0-or-later
*
* QEMU Motorola 680x0 IRQ Controller
*
* (c) 2020 Laurent Vivier <laurent@vivier.eu>
*
*/
#include "qemu/osdep.h"
#include "cpu.h"
#include "migration/vmstate.h"
#include "monitor/monitor.h"
#include "hw/nmi.h"
#include "hw/intc/intc.h"
#include "hw/intc/m68k_irqc.h"
static bool m68k_irqc_get_statistics(InterruptStatsProvider *obj,
uint64_t **irq_counts, unsigned int *nb_irqs)
{
M68KIRQCState *s = M68K_IRQC(obj);
*irq_counts = s->stats_irq_count;
*nb_irqs = ARRAY_SIZE(s->stats_irq_count);
return true;
}
static void m68k_irqc_print_info(InterruptStatsProvider *obj, Monitor *mon)
{
M68KIRQCState *s = M68K_IRQC(obj);
monitor_printf(mon, "m68k-irqc: ipr=0x%x\n", s->ipr);
}
static void m68k_set_irq(void *opaque, int irq, int level)
{
M68KIRQCState *s = opaque;
M68kCPU *cpu = M68K_CPU(first_cpu);
int i;
if (level) {
s->ipr |= 1 << irq;
s->stats_irq_count[irq]++;
} else {
s->ipr &= ~(1 << irq);
}
for (i = M68K_IRQC_LEVEL_7; i >= M68K_IRQC_LEVEL_1; i--) {
if ((s->ipr >> i) & 1) {
m68k_set_irq_level(cpu, i + 1, i + M68K_IRQC_AUTOVECTOR_BASE);
return;
}
}
m68k_set_irq_level(cpu, 0, 0);
}
static void m68k_irqc_reset(DeviceState *d)
{
M68KIRQCState *s = M68K_IRQC(d);
int i;
s->ipr = 0;
for (i = 0; i < ARRAY_SIZE(s->stats_irq_count); i++) {
s->stats_irq_count[i] = 0;
}
}
static void m68k_irqc_instance_init(Object *obj)
{
qdev_init_gpio_in(DEVICE(obj), m68k_set_irq, M68K_IRQC_LEVEL_NUM);
}
static void m68k_nmi(NMIState *n, int cpu_index, Error **errp)
{
m68k_set_irq(n, M68K_IRQC_LEVEL_7, 1);
}
static const VMStateDescription vmstate_m68k_irqc = {
.name = "m68k-irqc",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT8(ipr, M68KIRQCState),
VMSTATE_END_OF_LIST()
}
};
static void m68k_irqc_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
NMIClass *nc = NMI_CLASS(oc);
InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(oc);
nc->nmi_monitor_handler = m68k_nmi;
dc->reset = m68k_irqc_reset;
dc->vmsd = &vmstate_m68k_irqc;
ic->get_statistics = m68k_irqc_get_statistics;
ic->print_info = m68k_irqc_print_info;
}
static const TypeInfo m68k_irqc_type_info = {
.name = TYPE_M68K_IRQC,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(M68KIRQCState),
.instance_init = m68k_irqc_instance_init,
.class_init = m68k_irqc_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_NMI },
{ TYPE_INTERRUPT_STATS_PROVIDER },
{ }
},
};
static void q800_irq_register_types(void)
{
type_register_static(&m68k_irqc_type_info);
}
type_init(q800_irq_register_types);

View File

@ -57,3 +57,5 @@ specific_ss.add(when: 'CONFIG_PSERIES', if_true: files('xics_spapr.c', 'spapr_xi
specific_ss.add(when: 'CONFIG_XIVE', if_true: files('xive.c'))
specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XIVE'],
if_true: files('spapr_xive_kvm.c'))
specific_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c'))
specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c'))

View File

@ -239,3 +239,11 @@ xive_end_source_read(uint8_t end_blk, uint32_t end_idx, uint64_t addr) "END 0x%x
# pnv_xive.c
pnv_xive_ic_hw_trigger(uint64_t addr, uint64_t val) "@0x%"PRIx64" val=0x%"PRIx64
# goldfish_pic.c
goldfish_irq_request(void *dev, int idx, int irq, int level) "pic: %p goldfish-irq.%d irq: %d level: %d"
goldfish_pic_read(void *dev, int idx, unsigned int addr, unsigned int size, uint64_t value) "pic: %p goldfish-irq.%d reg: 0x%02x size: %d value: 0x%"PRIx64
goldfish_pic_write(void *dev, int idx, unsigned int addr, unsigned int size, uint64_t value) "pic: %p goldfish-irq.%d reg: 0x%02x size: %d value: 0x%"PRIx64
goldfish_pic_reset(void *dev, int idx) "pic: %p goldfish-irq.%d"
goldfish_pic_realize(void *dev, int idx) "pic: %p goldfish-irq.%d"
goldfish_pic_instance_init(void *dev) "pic: %p goldfish-irq"

View File

@ -23,3 +23,12 @@ config Q800
select ESP
select DP8393X
select OR_IRQ
config M68K_VIRT
bool
select M68K_IRQC
select VIRT_CTRL
select GOLDFISH_PIC
select GOLDFISH_TTY
select GOLDFISH_RTC
select VIRTIO_MMIO

View File

@ -3,5 +3,6 @@ m68k_ss.add(when: 'CONFIG_AN5206', if_true: files('an5206.c', 'mcf5206.c'))
m68k_ss.add(when: 'CONFIG_MCF5208', if_true: files('mcf5208.c', 'mcf_intc.c'))
m68k_ss.add(when: 'CONFIG_NEXTCUBE', if_true: files('next-kbd.c', 'next-cube.c'))
m68k_ss.add(when: 'CONFIG_Q800', if_true: files('q800.c'))
m68k_ss.add(when: 'CONFIG_M68K_VIRT', if_true: files('virt.c'))
hw_arch += {'m68k': m68k_ss}

313
hw/m68k/virt.c Normal file
View File

@ -0,0 +1,313 @@
/*
* SPDX-License-Identifer: GPL-2.0-or-later
*
* QEMU Vitual M68K Machine
*
* (c) 2020 Laurent Vivier <laurent@vivier.eu>
*
*/
#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 "hw/qdev-properties.h"
#include "elf.h"
#include "hw/loader.h"
#include "ui/console.h"
#include "exec/address-spaces.h"
#include "hw/sysbus.h"
#include "standard-headers/asm-m68k/bootinfo.h"
#include "standard-headers/asm-m68k/bootinfo-virt.h"
#include "bootinfo.h"
#include "net/net.h"
#include "qapi/error.h"
#include "sysemu/qtest.h"
#include "sysemu/runstate.h"
#include "sysemu/reset.h"
#include "hw/intc/m68k_irqc.h"
#include "hw/misc/virt_ctrl.h"
#include "hw/char/goldfish_tty.h"
#include "hw/rtc/goldfish_rtc.h"
#include "hw/intc/goldfish_pic.h"
#include "hw/virtio/virtio-mmio.h"
#include "hw/virtio/virtio-blk.h"
/*
* 6 goldfish-pic for CPU IRQ #1 to IRQ #6
* CPU IRQ #1 -> PIC #1
* IRQ #1 to IRQ #31 -> unused
* IRQ #32 -> goldfish-tty
* CPU IRQ #2 -> PIC #2
* IRQ #1 to IRQ #32 -> virtio-mmio from 1 to 32
* CPU IRQ #3 -> PIC #3
* IRQ #1 to IRQ #32 -> virtio-mmio from 33 to 64
* CPU IRQ #4 -> PIC #4
* IRQ #1 to IRQ #32 -> virtio-mmio from 65 to 96
* CPU IRQ #5 -> PIC #5
* IRQ #1 to IRQ #32 -> virtio-mmio from 97 to 128
* CPU IRQ #6 -> PIC #6
* IRQ #1 -> goldfish-rtc
* IRQ #2 to IRQ #32 -> unused
* CPU IRQ #7 -> NMI
*/
#define PIC_IRQ_BASE(num) (8 + (num - 1) * 32)
#define PIC_IRQ(num, irq) (PIC_IRQ_BASE(num) + irq - 1)
#define PIC_GPIO(pic_irq) (qdev_get_gpio_in(pic_dev[(pic_irq - 8) / 32], \
(pic_irq - 8) % 32))
#define VIRT_GF_PIC_MMIO_BASE 0xff000000 /* MMIO: 0xff000000 - 0xff005fff */
#define VIRT_GF_PIC_IRQ_BASE 1 /* IRQ: #1 -> #6 */
#define VIRT_GF_PIC_NB 6
/* 2 goldfish-rtc (and timer) */
#define VIRT_GF_RTC_MMIO_BASE 0xff006000 /* MMIO: 0xff006000 - 0xff007fff */
#define VIRT_GF_RTC_IRQ_BASE PIC_IRQ(6, 1) /* PIC: #6, IRQ: #1 */
#define VIRT_GF_RTC_NB 2
/* 1 goldfish-tty */
#define VIRT_GF_TTY_MMIO_BASE 0xff008000 /* MMIO: 0xff008000 - 0xff008fff */
#define VIRT_GF_TTY_IRQ_BASE PIC_IRQ(1, 32) /* PIC: #1, IRQ: #32 */
/* 1 virt-ctrl */
#define VIRT_CTRL_MMIO_BASE 0xff009000 /* MMIO: 0xff009000 - 0xff009fff */
#define VIRT_CTRL_IRQ_BASE PIC_IRQ(1, 1) /* PIC: #1, IRQ: #1 */
/*
* virtio-mmio size is 0x200 bytes
* we use 4 goldfish-pic to attach them,
* we can attach 32 virtio devices / goldfish-pic
* -> we can manage 32 * 4 = 128 virtio devices
*/
#define VIRT_VIRTIO_MMIO_BASE 0xff010000 /* MMIO: 0xff010000 - 0xff01ffff */
#define VIRT_VIRTIO_IRQ_BASE PIC_IRQ(2, 1) /* PIC: 2, 3, 4, 5, IRQ: ALL */
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 virt_init(MachineState *machine)
{
M68kCPU *cpu = NULL;
int32_t kernel_size;
uint64_t elf_entry;
ram_addr_t initrd_base;
int32_t initrd_size;
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;
DeviceState *dev;
DeviceState *irqc_dev;
DeviceState *pic_dev[VIRT_GF_PIC_NB];
SysBusDevice *sysbus;
hwaddr io_base;
int i;
if (ram_size > 3399672 * KiB) {
/*
* The physical memory can be up to 4 GiB - 16 MiB, but linux
* kernel crashes after this limit (~ 3.2 GiB)
*/
error_report("Too much memory for this machine: %" PRId64 " KiB, "
"maximum 3399672 KiB", ram_size / KiB);
exit(1);
}
/* init CPUs */
cpu = M68K_CPU(cpu_create(machine->cpu_type));
qemu_register_reset(main_cpu_reset, cpu);
/* RAM */
memory_region_add_subregion(get_system_memory(), 0, machine->ram);
/* IRQ Controller */
irqc_dev = qdev_new(TYPE_M68K_IRQC);
sysbus_realize_and_unref(SYS_BUS_DEVICE(irqc_dev), &error_fatal);
/*
* 6 goldfish-pic
*
* map: 0xff000000 - 0xff006fff = 28 KiB
* IRQ: #1 (lower priority) -> #6 (higher priority)
*
*/
io_base = VIRT_GF_PIC_MMIO_BASE;
for (i = 0; i < VIRT_GF_PIC_NB; i++) {
pic_dev[i] = qdev_new(TYPE_GOLDFISH_PIC);
sysbus = SYS_BUS_DEVICE(pic_dev[i]);
qdev_prop_set_uint8(pic_dev[i], "index", i);
sysbus_realize_and_unref(sysbus, &error_fatal);
sysbus_mmio_map(sysbus, 0, io_base);
sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(irqc_dev, i));
io_base += 0x1000;
}
/* goldfish-rtc */
io_base = VIRT_GF_RTC_MMIO_BASE;
for (i = 0; i < VIRT_GF_RTC_NB; i++) {
dev = qdev_new(TYPE_GOLDFISH_RTC);
sysbus = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(sysbus, &error_fatal);
sysbus_mmio_map(sysbus, 0, io_base);
sysbus_connect_irq(sysbus, 0, PIC_GPIO(VIRT_GF_RTC_IRQ_BASE + i));
io_base += 0x1000;
}
/* goldfish-tty */
dev = qdev_new(TYPE_GOLDFISH_TTY);
sysbus = SYS_BUS_DEVICE(dev);
qdev_prop_set_chr(dev, "chardev", serial_hd(0));
sysbus_realize_and_unref(sysbus, &error_fatal);
sysbus_mmio_map(sysbus, 0, VIRT_GF_TTY_MMIO_BASE);
sysbus_connect_irq(sysbus, 0, PIC_GPIO(VIRT_GF_TTY_IRQ_BASE));
/* virt controller */
dev = qdev_new(TYPE_VIRT_CTRL);
sysbus = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(sysbus, &error_fatal);
sysbus_mmio_map(sysbus, 0, VIRT_CTRL_MMIO_BASE);
sysbus_connect_irq(sysbus, 0, PIC_GPIO(VIRT_CTRL_IRQ_BASE));
/* virtio-mmio */
io_base = VIRT_VIRTIO_MMIO_BASE;
for (i = 0; i < 128; i++) {
dev = qdev_new(TYPE_VIRTIO_MMIO);
qdev_prop_set_bit(dev, "force-legacy", false);
sysbus = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(sysbus, &error_fatal);
sysbus_connect_irq(sysbus, 0, PIC_GPIO(VIRT_VIRTIO_IRQ_BASE + i));
sysbus_mmio_map(sysbus, 0, io_base);
io_base += 0x200;
}
if (kernel_filename) {
CPUState *cs = CPU(cpu);
uint64_t high;
kernel_size = load_elf(kernel_filename, NULL, NULL, NULL,
&elf_entry, NULL, &high, NULL, 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_VIRT);
BOOTINFO1(cs->as, parameters_base, BI_FPUTYPE, FPU_68040);
BOOTINFO1(cs->as, parameters_base, BI_MMUTYPE, MMU_68040);
BOOTINFO1(cs->as, parameters_base, BI_CPUTYPE, CPU_68040);
BOOTINFO2(cs->as, parameters_base, BI_MEMCHUNK, 0, ram_size);
BOOTINFO1(cs->as, parameters_base, BI_VIRT_QEMU_VERSION,
((QEMU_VERSION_MAJOR << 24) | (QEMU_VERSION_MINOR << 16) |
(QEMU_VERSION_MICRO << 8)));
BOOTINFO2(cs->as, parameters_base, BI_VIRT_GF_PIC_BASE,
VIRT_GF_PIC_MMIO_BASE, VIRT_GF_PIC_IRQ_BASE);
BOOTINFO2(cs->as, parameters_base, BI_VIRT_GF_RTC_BASE,
VIRT_GF_RTC_MMIO_BASE, VIRT_GF_RTC_IRQ_BASE);
BOOTINFO2(cs->as, parameters_base, BI_VIRT_GF_TTY_BASE,
VIRT_GF_TTY_MMIO_BASE, VIRT_GF_TTY_IRQ_BASE);
BOOTINFO2(cs->as, parameters_base, BI_VIRT_CTRL_BASE,
VIRT_CTRL_MMIO_BASE, VIRT_CTRL_IRQ_BASE);
BOOTINFO2(cs->as, parameters_base, BI_VIRT_VIRTIO_BASE,
VIRT_VIRTIO_MMIO_BASE, VIRT_VIRTIO_IRQ_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);
}
}
static void virt_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
mc->desc = "QEMU M68K Virtual Machine";
mc->init = virt_init;
mc->default_cpu_type = M68K_CPU_TYPE_NAME("m68040");
mc->max_cpus = 1;
mc->no_floppy = 1;
mc->no_parallel = 1;
mc->default_ram_id = "m68k_virt.ram";
}
static const TypeInfo virt_machine_info = {
.name = MACHINE_TYPE_NAME("virt"),
.parent = TYPE_MACHINE,
.abstract = true,
.class_init = virt_machine_class_init,
};
static void virt_machine_register_types(void)
{
type_register_static(&virt_machine_info);
}
type_init(virt_machine_register_types)
#define DEFINE_VIRT_MACHINE(major, minor, latest) \
static void virt_##major##_##minor##_class_init(ObjectClass *oc, \
void *data) \
{ \
MachineClass *mc = MACHINE_CLASS(oc); \
virt_machine_##major##_##minor##_options(mc); \
mc->desc = "QEMU " # major "." # minor " M68K Virtual Machine"; \
if (latest) { \
mc->alias = "virt"; \
} \
} \
static const TypeInfo machvirt_##major##_##minor##_info = { \
.name = MACHINE_TYPE_NAME("virt-" # major "." # minor), \
.parent = MACHINE_TYPE_NAME("virt"), \
.class_init = virt_##major##_##minor##_class_init, \
}; \
static void machvirt_machine_##major##_##minor##_init(void) \
{ \
type_register_static(&machvirt_##major##_##minor##_info); \
} \
type_init(machvirt_machine_##major##_##minor##_init);
static void virt_machine_6_0_options(MachineClass *mc)
{
}
DEFINE_VIRT_MACHINE(6, 0, true)

View File

@ -183,4 +183,7 @@ config SIFIVE_U_OTP
config SIFIVE_U_PRCI
bool
config VIRT_CTRL
bool
source macio/Kconfig

View File

@ -24,6 +24,9 @@ softmmu_ss.add(when: 'CONFIG_ARM11SCU', if_true: files('arm11scu.c'))
# Mac devices
softmmu_ss.add(when: 'CONFIG_MOS6522', if_true: files('mos6522.c'))
# virt devices
softmmu_ss.add(when: 'CONFIG_VIRT_CTRL', if_true: files('virt_ctrl.c'))
# RISC-V devices
softmmu_ss.add(when: 'CONFIG_MCHP_PFSOC_DMC', if_true: files('mchp_pfsoc_dmc.c'))
softmmu_ss.add(when: 'CONFIG_MCHP_PFSOC_IOSCB', if_true: files('mchp_pfsoc_ioscb.c'))

View File

@ -255,3 +255,10 @@ pca955x_gpio_change(const char *description, unsigned id, unsigned prev_state, u
bcm2835_cprman_read(uint64_t offset, uint64_t value) "offset:0x%" PRIx64 " value:0x%" PRIx64
bcm2835_cprman_write(uint64_t offset, uint64_t value) "offset:0x%" PRIx64 " value:0x%" PRIx64
bcm2835_cprman_write_invalid_magic(uint64_t offset, uint64_t value) "offset:0x%" PRIx64 " value:0x%" PRIx64
# virt_ctrl.c
virt_ctrl_read(void *dev, unsigned int addr, unsigned int size, uint64_t value) "ctrl: %p reg: 0x%02x size: %d value: 0x%"PRIx64
virt_ctrl_write(void *dev, unsigned int addr, unsigned int size, uint64_t value) "ctrl: %p reg: 0x%02x size: %d value: 0x%"PRIx64
virt_ctrl_reset(void *dev) "ctrl: %p"
virt_ctrl_realize(void *dev) "ctrl: %p"
virt_ctrl_instance_init(void *dev) "ctrl: %p"

151
hw/misc/virt_ctrl.c Normal file
View File

@ -0,0 +1,151 @@
/*
* SPDX-License-Identifer: GPL-2.0-or-later
*
* Virt system Controller
*/
#include "qemu/osdep.h"
#include "hw/irq.h"
#include "hw/qdev-properties.h"
#include "hw/sysbus.h"
#include "migration/vmstate.h"
#include "qemu/log.h"
#include "trace.h"
#include "sysemu/runstate.h"
#include "hw/misc/virt_ctrl.h"
enum {
REG_FEATURES = 0x00,
REG_CMD = 0x04,
};
#define FEAT_POWER_CTRL 0x00000001
enum {
CMD_NOOP,
CMD_RESET,
CMD_HALT,
CMD_PANIC,
};
static uint64_t virt_ctrl_read(void *opaque, hwaddr addr, unsigned size)
{
VirtCtrlState *s = opaque;
uint64_t value = 0;
switch (addr) {
case REG_FEATURES:
value = FEAT_POWER_CTRL;
break;
default:
qemu_log_mask(LOG_UNIMP,
"%s: unimplemented register read 0x%02"HWADDR_PRIx"\n",
__func__, addr);
break;
}
trace_virt_ctrl_write(s, addr, size, value);
return value;
}
static void virt_ctrl_write(void *opaque, hwaddr addr, uint64_t value,
unsigned size)
{
VirtCtrlState *s = opaque;
trace_virt_ctrl_write(s, addr, size, value);
switch (addr) {
case REG_CMD:
switch (value) {
case CMD_NOOP:
break;
case CMD_RESET:
qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
break;
case CMD_HALT:
qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
break;
case CMD_PANIC:
qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_PANIC);
break;
}
break;
default:
qemu_log_mask(LOG_UNIMP,
"%s: unimplemented register write 0x%02"HWADDR_PRIx"\n",
__func__, addr);
break;
}
}
static const MemoryRegionOps virt_ctrl_ops = {
.read = virt_ctrl_read,
.write = virt_ctrl_write,
.endianness = DEVICE_NATIVE_ENDIAN,
.valid.max_access_size = 4,
.impl.max_access_size = 4,
};
static void virt_ctrl_reset(DeviceState *dev)
{
VirtCtrlState *s = VIRT_CTRL(dev);
trace_virt_ctrl_reset(s);
}
static void virt_ctrl_realize(DeviceState *dev, Error **errp)
{
VirtCtrlState *s = VIRT_CTRL(dev);
trace_virt_ctrl_instance_init(s);
memory_region_init_io(&s->iomem, OBJECT(s), &virt_ctrl_ops, s,
"virt-ctrl", 0x100);
}
static const VMStateDescription vmstate_virt_ctrl = {
.name = "virt-ctrl",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32(irq_enabled, VirtCtrlState),
VMSTATE_END_OF_LIST()
}
};
static void virt_ctrl_instance_init(Object *obj)
{
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
VirtCtrlState *s = VIRT_CTRL(obj);
trace_virt_ctrl_instance_init(s);
sysbus_init_mmio(dev, &s->iomem);
sysbus_init_irq(dev, &s->irq);
}
static void virt_ctrl_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->reset = virt_ctrl_reset;
dc->realize = virt_ctrl_realize;
dc->vmsd = &vmstate_virt_ctrl;
}
static const TypeInfo virt_ctrl_info = {
.name = TYPE_VIRT_CTRL,
.parent = TYPE_SYS_BUS_DEVICE,
.class_init = virt_ctrl_class_init,
.instance_init = virt_ctrl_instance_init,
.instance_size = sizeof(VirtCtrlState),
};
static void virt_ctrl_register_types(void)
{
type_register_static(&virt_ctrl_info);
}
type_init(virt_ctrl_register_types)

View File

@ -0,0 +1,35 @@
/*
* SPDX-License-Identifer: GPL-2.0-or-later
*
* Goldfish TTY
*
* (c) 2020 Laurent Vivier <laurent@vivier.eu>
*
*/
#ifndef HW_CHAR_GOLDFISH_TTY_H
#define HW_CHAR_GOLDFISH_TTY_H
#include "qemu/fifo8.h"
#include "chardev/char-fe.h"
#define TYPE_GOLDFISH_TTY "goldfish_tty"
OBJECT_DECLARE_SIMPLE_TYPE(GoldfishTTYState, GOLDFISH_TTY)
#define GOLFISH_TTY_BUFFER_SIZE 128
struct GoldfishTTYState {
SysBusDevice parent_obj;
MemoryRegion iomem;
qemu_irq irq;
CharBackend chr;
uint32_t data_len;
uint64_t data_ptr;
bool int_enabled;
Fifo8 rx_fifo;
};
#endif

View File

@ -0,0 +1,33 @@
/*
* SPDX-License-Identifer: GPL-2.0-or-later
*
* Goldfish PIC
*
* (c) 2020 Laurent Vivier <laurent@vivier.eu>
*
*/
#ifndef HW_INTC_GOLDFISH_PIC_H
#define HW_INTC_GOLDFISH_PIC_H
#define TYPE_GOLDFISH_PIC "goldfish_pic"
OBJECT_DECLARE_SIMPLE_TYPE(GoldfishPICState, GOLDFISH_PIC)
#define GOLDFISH_PIC_IRQ_NB 32
struct GoldfishPICState {
SysBusDevice parent_obj;
MemoryRegion iomem;
qemu_irq irq;
uint32_t pending;
uint32_t enabled;
/* statistics */
uint64_t stats_irq_count[32];
/* for tracing */
uint8_t idx;
};
#endif

View File

@ -0,0 +1,41 @@
/*
* SPDX-License-Identifer: GPL-2.0-or-later
*
* QEMU Motorola 680x0 IRQ Controller
*
* (c) 2020 Laurent Vivier <laurent@vivier.eu>
*
*/
#ifndef M68K_IRQC_H
#define M68K_IRQC_H
#include "hw/sysbus.h"
#define TYPE_M68K_IRQC "m68k-irq-controller"
#define M68K_IRQC(obj) OBJECT_CHECK(M68KIRQCState, (obj), \
TYPE_M68K_IRQC)
#define M68K_IRQC_AUTOVECTOR_BASE 25
enum {
M68K_IRQC_LEVEL_1 = 0,
M68K_IRQC_LEVEL_2,
M68K_IRQC_LEVEL_3,
M68K_IRQC_LEVEL_4,
M68K_IRQC_LEVEL_5,
M68K_IRQC_LEVEL_6,
M68K_IRQC_LEVEL_7,
};
#define M68K_IRQC_LEVEL_NUM (M68K_IRQC_LEVEL_7 - M68K_IRQC_LEVEL_1 + 1)
typedef struct M68KIRQCState {
SysBusDevice parent_obj;
uint8_t ipr;
/* statistics */
uint64_t stats_irq_count[M68K_IRQC_LEVEL_NUM];
} M68KIRQCState;
#endif

View File

@ -0,0 +1,22 @@
/*
* SPDX-License-Identifer: GPL-2.0-or-later
*
* Virt system Controller
*/
#ifndef VIRT_CTRL_H
#define VIRT_CTRL_H
#define TYPE_VIRT_CTRL "virt-ctrl"
OBJECT_DECLARE_SIMPLE_TYPE(VirtCtrlState, VIRT_CTRL)
struct VirtCtrlState {
SysBusDevice parent_obj;
MemoryRegion iomem;
qemu_irq irq;
uint32_t irq_enabled;
};
#endif

View File

@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/*
** asm/bootinfo-virt.h -- Virtual-m68k-specific boot information definitions
*/
#ifndef _UAPI_ASM_M68K_BOOTINFO_VIRT_H
#define _UAPI_ASM_M68K_BOOTINFO_VIRT_H
#define BI_VIRT_QEMU_VERSION 0x8000
#define BI_VIRT_GF_PIC_BASE 0x8001
#define BI_VIRT_GF_RTC_BASE 0x8002
#define BI_VIRT_GF_TTY_BASE 0x8003
#define BI_VIRT_VIRTIO_BASE 0x8004
#define BI_VIRT_CTRL_BASE 0x8005
#define VIRT_BOOTI_VERSION MK_BI_VERSION(2, 0)
#endif /* _UAPI_ASM_M68K_BOOTINFO_MAC_H */