* [PATCH 1/4] m68k: import bootinfo headers from linux
2020-10-13 15:51 [PATCH 0/4] m68k: add Virtual M68k Machine Laurent Vivier
@ 2020-10-13 15:51 ` Laurent Vivier
2020-10-13 15:51 ` [PATCH 2/4] char: add goldfish-tty Laurent Vivier
` (2 subsequent siblings)
3 siblings, 0 replies; 7+ messages in thread
From: Laurent Vivier @ 2020-10-13 15:51 UTC (permalink / raw)
To: qemu-devel; +Cc: Laurent Vivier
Copy bootinfo.h and bootinfo-mac.h from arch/m68k/include/uapi/asm/
to include/standard-headers/asm-m68k/
Imported from linx v5.9 but didn't change since v4.14 (header update)
and since v4.10 (content update).
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
hw/m68k/bootinfo.h | 55 ------
.../standard-headers/asm-m68k/bootinfo-mac.h | 120 +++++++++++++
include/standard-headers/asm-m68k/bootinfo.h | 166 ++++++++++++++++++
hw/m68k/q800.c | 20 +--
MAINTAINERS | 2 +
5 files changed, 295 insertions(+), 68 deletions(-)
create mode 100644 include/standard-headers/asm-m68k/bootinfo-mac.h
create mode 100644 include/standard-headers/asm-m68k/bootinfo.h
diff --git a/hw/m68k/bootinfo.h b/hw/m68k/bootinfo.h
index c954270aad6c..adbf0c5521e5 100644
--- a/hw/m68k/bootinfo.h
+++ b/hw/m68k/bootinfo.h
@@ -11,61 +11,6 @@
#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[]; /* 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 { \
diff --git a/include/standard-headers/asm-m68k/bootinfo-mac.h b/include/standard-headers/asm-m68k/bootinfo-mac.h
new file mode 100644
index 000000000000..449928cfcbf2
--- /dev/null
+++ b/include/standard-headers/asm-m68k/bootinfo-mac.h
@@ -0,0 +1,120 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+** asm/bootinfo-mac.h -- Macintosh-specific boot information definitions
+*/
+
+#ifndef _UAPI_ASM_M68K_BOOTINFO_MAC_H
+#define _UAPI_ASM_M68K_BOOTINFO_MAC_H
+
+
+ /*
+ * Macintosh-specific tags (all __be32)
+ */
+
+#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 - unused, see macintosh.h for
+ * reasonable type values
+ */
+
+#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 */
+
+
+ /*
+ * Macintosh Gestalt numbers (BI_MAC_MODEL)
+ */
+
+#define MAC_MODEL_II 6
+#define MAC_MODEL_IIX 7
+#define MAC_MODEL_IICX 8
+#define MAC_MODEL_SE30 9
+#define MAC_MODEL_IICI 11
+#define MAC_MODEL_IIFX 13 /* And well numbered it is too */
+#define MAC_MODEL_IISI 18
+#define MAC_MODEL_LC 19
+#define MAC_MODEL_Q900 20
+#define MAC_MODEL_PB170 21
+#define MAC_MODEL_Q700 22
+#define MAC_MODEL_CLII 23 /* aka: P200 */
+#define MAC_MODEL_PB140 25
+#define MAC_MODEL_Q950 26 /* aka: WGS95 */
+#define MAC_MODEL_LCIII 27 /* aka: P450 */
+#define MAC_MODEL_PB210 29
+#define MAC_MODEL_C650 30
+#define MAC_MODEL_PB230 32
+#define MAC_MODEL_PB180 33
+#define MAC_MODEL_PB160 34
+#define MAC_MODEL_Q800 35 /* aka: WGS80 */
+#define MAC_MODEL_Q650 36
+#define MAC_MODEL_LCII 37 /* aka: P400/405/410/430 */
+#define MAC_MODEL_PB250 38
+#define MAC_MODEL_IIVI 44
+#define MAC_MODEL_P600 45 /* aka: P600CD */
+#define MAC_MODEL_IIVX 48
+#define MAC_MODEL_CCL 49 /* aka: P250 */
+#define MAC_MODEL_PB165C 50
+#define MAC_MODEL_C610 52 /* aka: WGS60 */
+#define MAC_MODEL_Q610 53
+#define MAC_MODEL_PB145 54 /* aka: PB145B */
+#define MAC_MODEL_P520 56 /* aka: LC520 */
+#define MAC_MODEL_C660 60
+#define MAC_MODEL_P460 62 /* aka: LCIII+, P466/P467 */
+#define MAC_MODEL_PB180C 71
+#define MAC_MODEL_PB520 72 /* aka: PB520C, PB540, PB540C, PB550C */
+#define MAC_MODEL_PB270C 77
+#define MAC_MODEL_Q840 78
+#define MAC_MODEL_P550 80 /* aka: LC550, P560 */
+#define MAC_MODEL_CCLII 83 /* aka: P275 */
+#define MAC_MODEL_PB165 84
+#define MAC_MODEL_PB190 85 /* aka: PB190CS */
+#define MAC_MODEL_TV 88
+#define MAC_MODEL_P475 89 /* aka: LC475, P476 */
+#define MAC_MODEL_P475F 90 /* aka: P475 w/ FPU (no LC040) */
+#define MAC_MODEL_P575 92 /* aka: LC575, P577/P578 */
+#define MAC_MODEL_Q605 94
+#define MAC_MODEL_Q605_ACC 95 /* Q605 accelerated to 33 MHz */
+#define MAC_MODEL_Q630 98 /* aka: LC630, P630/631/635/636/637/638/640 */
+#define MAC_MODEL_P588 99 /* aka: LC580, P580 */
+#define MAC_MODEL_PB280 102
+#define MAC_MODEL_PB280C 103
+#define MAC_MODEL_PB150 115
+
+
+ /*
+ * Latest Macintosh bootinfo version
+ */
+
+#define MAC_BOOTI_VERSION MK_BI_VERSION(2, 0)
+
+
+#endif /* _UAPI_ASM_M68K_BOOTINFO_MAC_H */
diff --git a/include/standard-headers/asm-m68k/bootinfo.h b/include/standard-headers/asm-m68k/bootinfo.h
new file mode 100644
index 000000000000..7b790e8ec8d6
--- /dev/null
+++ b/include/standard-headers/asm-m68k/bootinfo.h
@@ -0,0 +1,166 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * asm/bootinfo.h -- Definition of the Linux/m68k boot information structure
+ *
+ * Copyright 1992 by Greg Harp
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _UAPI_ASM_M68K_BOOTINFO_H
+#define _UAPI_ASM_M68K_BOOTINFO_H
+
+
+ /*
+ * Bootinfo definitions
+ *
+ * This is an easily parsable and extendable structure containing all
+ * information to be passed from the bootstrap to the kernel.
+ *
+ * This way I hope to keep all future changes back/forewards compatible.
+ * Thus, keep your fingers crossed...
+ *
+ * This structure is copied right after the kernel by the bootstrap
+ * routine.
+ */
+
+struct bi_record {
+ uint16_t tag; /* tag ID */
+ uint16_t size; /* size of record (in bytes) */
+ uint32_t data[0]; /* data */
+};
+
+
+struct mem_info {
+ uint32_t addr; /* physical address of memory chunk */
+ uint32_t size; /* length of memory chunk (in bytes) */
+};
+
+
+ /*
+ * Tag Definitions
+ *
+ * Machine independent tags start counting from 0x0000
+ * Machine dependent tags start counting from 0x8000
+ */
+
+#define BI_LAST 0x0000 /* last record (sentinel) */
+#define BI_MACHTYPE 0x0001 /* machine type (uint32_t) */
+#define BI_CPUTYPE 0x0002 /* cpu type (uint32_t) */
+#define BI_FPUTYPE 0x0003 /* fpu type (uint32_t) */
+#define BI_MMUTYPE 0x0004 /* mmu type (uint32_t) */
+#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) */
+
+
+ /*
+ * Linux/m68k Architectures (BI_MACHTYPE)
+ */
+
+#define MACH_AMIGA 1
+#define MACH_ATARI 2
+#define MACH_MAC 3
+#define MACH_APOLLO 4
+#define MACH_SUN3 5
+#define MACH_MVME147 6
+#define MACH_MVME16x 7
+#define MACH_BVME6000 8
+#define MACH_HP300 9
+#define MACH_Q40 10
+#define MACH_SUN3X 11
+#define MACH_M54XX 12
+#define MACH_M5441X 13
+#define MACH_VIRT 14
+
+
+ /*
+ * CPU, FPU and MMU types (BI_CPUTYPE, BI_FPUTYPE, BI_MMUTYPE)
+ *
+ * Note: we may rely on the following equalities:
+ *
+ * CPU_68020 == MMU_68851
+ * CPU_68030 == MMU_68030
+ * CPU_68040 == FPU_68040 == MMU_68040
+ * CPU_68060 == FPU_68060 == MMU_68060
+ */
+
+#define CPUB_68020 0
+#define CPUB_68030 1
+#define CPUB_68040 2
+#define CPUB_68060 3
+#define CPUB_COLDFIRE 4
+
+#define CPU_68020 (1 << CPUB_68020)
+#define CPU_68030 (1 << CPUB_68030)
+#define CPU_68040 (1 << CPUB_68040)
+#define CPU_68060 (1 << CPUB_68060)
+#define CPU_COLDFIRE (1 << CPUB_COLDFIRE)
+
+#define FPUB_68881 0
+#define FPUB_68882 1
+#define FPUB_68040 2 /* Internal FPU */
+#define FPUB_68060 3 /* Internal FPU */
+#define FPUB_SUNFPA 4 /* Sun-3 FPA */
+#define FPUB_COLDFIRE 5 /* ColdFire FPU */
+
+#define FPU_68881 (1 << FPUB_68881)
+#define FPU_68882 (1 << FPUB_68882)
+#define FPU_68040 (1 << FPUB_68040)
+#define FPU_68060 (1 << FPUB_68060)
+#define FPU_SUNFPA (1 << FPUB_SUNFPA)
+#define FPU_COLDFIRE (1 << FPUB_COLDFIRE)
+
+#define MMUB_68851 0
+#define MMUB_68030 1 /* Internal MMU */
+#define MMUB_68040 2 /* Internal MMU */
+#define MMUB_68060 3 /* Internal MMU */
+#define MMUB_APOLLO 4 /* Custom Apollo */
+#define MMUB_SUN3 5 /* Custom Sun-3 */
+#define MMUB_COLDFIRE 6 /* Internal MMU */
+
+#define MMU_68851 (1 << MMUB_68851)
+#define MMU_68030 (1 << MMUB_68030)
+#define MMU_68040 (1 << MMUB_68040)
+#define MMU_68060 (1 << MMUB_68060)
+#define MMU_SUN3 (1 << MMUB_SUN3)
+#define MMU_APOLLO (1 << MMUB_APOLLO)
+#define MMU_COLDFIRE (1 << MMUB_COLDFIRE)
+
+
+ /*
+ * Stuff for bootinfo interface versioning
+ *
+ * At the start of kernel code, a 'struct bootversion' is located.
+ * bootstrap checks for a matching version of the interface before booting
+ * a kernel, to avoid user confusion if kernel and bootstrap don't work
+ * together :-)
+ *
+ * If incompatible changes are made to the bootinfo interface, the major
+ * number below should be stepped (and the minor reset to 0) for the
+ * appropriate machine. If a change is backward-compatible, the minor
+ * should be stepped. "Backwards-compatible" means that booting will work,
+ * but certain features may not.
+ */
+
+#define BOOTINFOV_MAGIC 0x4249561A /* 'BIV^Z' */
+#define MK_BI_VERSION(major, minor) (((major) << 16) + (minor))
+#define BI_VERSION_MAJOR(v) (((v) >> 16) & 0xffff)
+#define BI_VERSION_MINOR(v) ((v) & 0xffff)
+
+struct bootversion {
+ uint16_t branch;
+ uint32_t magic;
+ struct {
+ uint32_t machtype;
+ uint32_t version;
+ } machversions[0];
+} QEMU_PACKED;
+
+
+#endif /* _UAPI_ASM_M68K_BOOTINFO_H */
diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c
index ce4b47c3e34d..961044b3aca1 100644
--- a/hw/m68k/q800.c
+++ b/hw/m68k/q800.c
@@ -35,6 +35,8 @@
#include "hw/char/escc.h"
#include "hw/sysbus.h"
#include "hw/scsi/esp.h"
+#include "standard-headers/asm-m68k/bootinfo.h"
+#include "standard-headers/asm-m68k/bootinfo-mac.h"
#include "bootinfo.h"
#include "hw/misc/mac_via.h"
#include "hw/input/adb.h"
@@ -52,14 +54,6 @@
#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 IO_BASE 0x50000000
#define IO_SLICE 0x00040000
#define IO_SIZE 0x04000000
@@ -348,11 +342,11 @@ static void q800_init(MachineState *machine)
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_FPUTYPE, FPU_68040);
+ BOOTINFO1(cs->as, parameters_base, BI_MMUTYPE, MMU_68040);
+ BOOTINFO1(cs->as, parameters_base, BI_CPUTYPE, CPU_68040);
+ BOOTINFO1(cs->as, parameters_base, BI_MAC_CPUID, CPUB_68040);
+ BOOTINFO1(cs->as, parameters_base, BI_MAC_MODEL, MAC_MODEL_Q800);
BOOTINFO1(cs->as, parameters_base,
BI_MAC_MEMSIZE, ram_size >> 20); /* in MB */
BOOTINFO2(cs->as, parameters_base, BI_MEMCHUNK, 0, ram_size);
diff --git a/MAINTAINERS b/MAINTAINERS
index 47dd38a8cc5d..d0962a22e1b4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1094,6 +1094,8 @@ F: hw/nubus/*
F: hw/display/macfb.c
F: hw/block/swim.c
F: hw/m68k/bootinfo.h
+F: include/standard-headers/asm-m68k/bootinfo.h
+F: include/standard-headers/asm-m68k/bootinfo-mac.h
F: include/hw/misc/mac_via.h
F: include/hw/nubus/*
F: include/hw/display/macfb.h
--
2.26.2
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 2/4] char: add goldfish-tty
2020-10-13 15:51 [PATCH 0/4] m68k: add Virtual M68k Machine Laurent Vivier
2020-10-13 15:51 ` [PATCH 1/4] m68k: import bootinfo headers from linux Laurent Vivier
@ 2020-10-13 15:51 ` Laurent Vivier
2020-10-13 15:51 ` [PATCH 3/4] intc: add goldfish-pic Laurent Vivier
2020-10-13 15:51 ` [PATCH 4/4] m68k: add Virtual M68k Machine Laurent Vivier
3 siblings, 0 replies; 7+ messages in thread
From: Laurent Vivier @ 2020-10-13 15:51 UTC (permalink / raw)
To: qemu-devel; +Cc: Laurent Vivier
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
include/hw/char/goldfish_tty.h | 36 +++++
hw/char/goldfish_tty.c | 265 +++++++++++++++++++++++++++++++++
hw/char/Kconfig | 3 +
hw/char/meson.build | 2 +
hw/char/trace-events | 9 ++
5 files changed, 315 insertions(+)
create mode 100644 include/hw/char/goldfish_tty.h
create mode 100644 hw/char/goldfish_tty.c
diff --git a/include/hw/char/goldfish_tty.h b/include/hw/char/goldfish_tty.h
new file mode 100644
index 000000000000..84d78f8cff54
--- /dev/null
+++ b/include/hw/char/goldfish_tty.h
@@ -0,0 +1,36 @@
+/*
+ * 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 "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;
+
+ uint32_t data_in_count;
+ uint8_t data_in[GOLFISH_TTY_BUFFER_SIZE];
+ uint8_t data_out[GOLFISH_TTY_BUFFER_SIZE];
+};
+
+#endif
diff --git a/hw/char/goldfish_tty.c b/hw/char/goldfish_tty.c
new file mode 100644
index 000000000000..16cab94f333d
--- /dev/null
+++ b/hw/char/goldfish_tty.c
@@ -0,0 +1,265 @@
+/*
+ * 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.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"
+
+/* 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 = s->data_in_count;
+ break;
+ case REG_VERSION:
+ value = 0;
+ 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)
+{
+ int to_copy;
+
+ switch (cmd) {
+ case CMD_INT_DISABLE:
+ if (s->int_enabled) {
+ if (s->data_in_count) {
+ qemu_set_irq(s->irq, 0);
+ }
+ s->int_enabled = false;
+ }
+ break;
+ case CMD_INT_ENABLE:
+ if (!s->int_enabled) {
+ if (s->data_in_count) {
+ qemu_set_irq(s->irq, 1);
+ }
+ s->int_enabled = true;
+ }
+ break;
+ case CMD_WRITE_BUFFER:
+ to_copy = s->data_len;
+ while (to_copy) {
+ int len;
+
+ len = MIN(GOLFISH_TTY_BUFFER_SIZE, to_copy);
+
+ address_space_rw(&address_space_memory, s->data_ptr,
+ MEMTXATTRS_UNSPECIFIED, s->data_out, len, 0);
+ to_copy -= len;
+ qemu_chr_fe_write_all(&s->chr, s->data_out, len);
+ }
+ break;
+ case CMD_READ_BUFFER:
+ to_copy = MIN(s->data_len, s->data_in_count);
+ address_space_rw(&address_space_memory, s->data_ptr,
+ MEMTXATTRS_UNSPECIFIED, s->data_in, to_copy, 1);
+ s->data_in_count -= to_copy;
+ memmove(s->data_in, s->data_in + to_copy, s->data_in_count);
+ if (s->int_enabled && !s->data_in_count) {
+ 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 = (value << 32) | (uint32_t)s->data_ptr;
+ 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,
+};
+
+static int goldfish_tty_can_receive(void *opaque)
+{
+ GoldfishTTYState *s = opaque;
+ int available = GOLFISH_TTY_BUFFER_SIZE - s->data_in_count;
+
+ 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 <= GOLFISH_TTY_BUFFER_SIZE - s->data_in_count);
+
+ memcpy(s->data_in + s->data_in_count, buffer, size);
+ s->data_in_count += size;
+
+ if (s->int_enabled && s->data_in_count) {
+ qemu_set_irq(s->irq, 1);
+ }
+}
+
+static void goldfish_tty_reset(DeviceState *dev)
+{
+ GoldfishTTYState *s = GOLDFISH_TTY(dev);
+
+ trace_goldfish_tty_reset(s);
+
+ memset(s->data_in, 0, GOLFISH_TTY_BUFFER_SIZE);
+ memset(s->data_out, 0, GOLFISH_TTY_BUFFER_SIZE);
+ s->data_in_count = 0;
+ 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);
+
+ 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 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_UINT32(data_in_count, GoldfishTTYState),
+ VMSTATE_BUFFER(data_in, GoldfishTTYState),
+ VMSTATE_BUFFER(data_out, GoldfishTTYState),
+ }
+};
+
+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->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)
diff --git a/hw/char/Kconfig b/hw/char/Kconfig
index 939bc4475883..a8bf0c6a7708 100644
--- a/hw/char/Kconfig
+++ b/hw/char/Kconfig
@@ -61,3 +61,6 @@ config MCHP_PFSOC_MMUART
config SIFIVE_UART
bool
+
+config GOLDFISH_TTY
+ bool
diff --git a/hw/char/meson.build b/hw/char/meson.build
index 196ac91fa29a..69d974873606 100644
--- a/hw/char/meson.build
+++ b/hw/char/meson.build
@@ -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'))
diff --git a/hw/char/trace-events b/hw/char/trace-events
index 609df10fed41..88b4a6b92e39 100644
--- a/hw/char/trace-events
+++ b/hw/char/trace-events
@@ -20,6 +20,15 @@ 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_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"
--
2.26.2
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 3/4] intc: add goldfish-pic
2020-10-13 15:51 [PATCH 0/4] m68k: add Virtual M68k Machine Laurent Vivier
2020-10-13 15:51 ` [PATCH 1/4] m68k: import bootinfo headers from linux Laurent Vivier
2020-10-13 15:51 ` [PATCH 2/4] char: add goldfish-tty Laurent Vivier
@ 2020-10-13 15:51 ` Laurent Vivier
2020-10-13 15:51 ` [PATCH 4/4] m68k: add Virtual M68k Machine Laurent Vivier
3 siblings, 0 replies; 7+ messages in thread
From: Laurent Vivier @ 2020-10-13 15:51 UTC (permalink / raw)
To: qemu-devel; +Cc: Laurent Vivier
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
include/hw/intc/goldfish_pic.h | 28 ++++++
hw/intc/goldfish_pic.c | 178 +++++++++++++++++++++++++++++++++
hw/intc/Kconfig | 3 +
hw/intc/meson.build | 1 +
hw/intc/trace-events | 8 ++
5 files changed, 218 insertions(+)
create mode 100644 include/hw/intc/goldfish_pic.h
create mode 100644 hw/intc/goldfish_pic.c
diff --git a/include/hw/intc/goldfish_pic.h b/include/hw/intc/goldfish_pic.h
new file mode 100644
index 000000000000..7886caf9df66
--- /dev/null
+++ b/include/hw/intc/goldfish_pic.h
@@ -0,0 +1,28 @@
+/*
+ * 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;
+};
+
+#endif
diff --git a/hw/intc/goldfish_pic.c b/hw/intc/goldfish_pic.c
new file mode 100644
index 000000000000..9007928e0aca
--- /dev/null
+++ b/hw/intc/goldfish_pic.c
@@ -0,0 +1,178 @@
+/*
+ * 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 "qemu/log.h"
+#include "trace.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 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, irq, level);
+
+ if (level) {
+ s->pending |= 1 << 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, 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, 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.max_access_size = 4,
+};
+
+static void goldfish_pic_reset(DeviceState *dev)
+{
+ GoldfishPICState *s = GOLDFISH_PIC(dev);
+
+ trace_goldfish_pic_reset(s);
+ s->pending = 0;
+ s->enabled = 0;
+}
+
+static void goldfish_pic_realize(DeviceState *dev, Error **errp)
+{
+ GoldfishPICState *s = GOLDFISH_PIC(dev);
+
+ trace_goldfish_pic_realize(s);
+
+ 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),
+ }
+};
+
+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 void goldfish_pic_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->reset = goldfish_pic_reset;
+ dc->realize = goldfish_pic_realize;
+ dc->vmsd = &vmstate_goldfish_pic;
+}
+
+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),
+};
+
+static void goldfish_pic_register_types(void)
+{
+ type_register_static(&goldfish_pic_info);
+}
+
+type_init(goldfish_pic_register_types)
diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
index d07954086a59..7ed79e7ac29f 100644
--- a/hw/intc/Kconfig
+++ b/hw/intc/Kconfig
@@ -73,3 +73,6 @@ config SIFIVE_CLINT
config SIFIVE_PLIC
bool
+
+config GOLDFISH_PIC
+ bool
diff --git a/hw/intc/meson.build b/hw/intc/meson.build
index 3f82cc230ad7..395bc2f64036 100644
--- a/hw/intc/meson.build
+++ b/hw/intc/meson.build
@@ -55,3 +55,4 @@ specific_ss.add(when: 'CONFIG_XICS_SPAPR', if_true: files('xics_spapr.c'))
specific_ss.add(when: 'CONFIG_XIVE', if_true: files('xive.c'))
specific_ss.add(when: 'CONFIG_XIVE_KVM', if_true: files('spapr_xive_kvm.c'))
specific_ss.add(when: 'CONFIG_XIVE_SPAPR', if_true: files('spapr_xive.c'))
+specific_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c'))
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index 527c3f76caed..4b4c679c8b41 100644
--- a/hw/intc/trace-events
+++ b/hw/intc/trace-events
@@ -199,3 +199,11 @@ nvic_sysreg_write(uint64_t addr, uint32_t value, unsigned size) "NVIC sysreg wri
heathrow_write(uint64_t addr, unsigned int n, uint64_t value) "0x%"PRIx64" %u: 0x%"PRIx64
heathrow_read(uint64_t addr, unsigned int n, uint64_t value) "0x%"PRIx64" %u: 0x%"PRIx64
heathrow_set_irq(int num, int level) "set_irq: num=0x%02x level=%d"
+
+# # goldfish_pic.c
+goldfish_irq_request(void *dev, int irq, int level) "pic: %p irq: %d level: %d"
+goldfish_pic_read(void *dev, unsigned int addr, unsigned int size, uint64_t value) "pic: %p reg: 0x%02x size: %d value: 0x%"PRIx64
+goldfish_pic_write(void *dev, unsigned int addr, unsigned int size, uint64_t value) "pic: %p reg: 0x%02x size: %d value: 0x%"PRIx64
+goldfish_pic_reset(void *dev) "pic: %p"
+goldfish_pic_realize(void *dev) "pic: %p"
+goldfish_pic_instance_init(void *dev) "pic: %p"
--
2.26.2
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 4/4] m68k: add Virtual M68k Machine
2020-10-13 15:51 [PATCH 0/4] m68k: add Virtual M68k Machine Laurent Vivier
` (2 preceding siblings ...)
2020-10-13 15:51 ` [PATCH 3/4] intc: add goldfish-pic Laurent Vivier
@ 2020-10-13 15:51 ` Laurent Vivier
2020-10-13 17:56 ` Philippe Mathieu-Daudé
3 siblings, 1 reply; 7+ messages in thread
From: Laurent Vivier @ 2020-10-13 15:51 UTC (permalink / raw)
To: qemu-devel; +Cc: Laurent Vivier
The machine is based on Goldfish interfaces defined by Google
for Android simulator. It uses Goldfish-rtc (timer and RTC),
Goldfish-pic (PIC) and Goldfish-tty (for serial port and early tty).
The machine is created with 128 virtio-mmio bus, and they can
be used to use serial console, GPU, disk, NIC, HID, ...
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
default-configs/devices/m68k-softmmu.mak | 1 +
.../standard-headers/asm-m68k/bootinfo-virt.h | 17 +
hw/m68k/virt.c | 296 ++++++++++++++++++
MAINTAINERS | 9 +
hw/m68k/Kconfig | 8 +
hw/m68k/meson.build | 1 +
6 files changed, 332 insertions(+)
create mode 100644 include/standard-headers/asm-m68k/bootinfo-virt.h
create mode 100644 hw/m68k/virt.c
diff --git a/default-configs/devices/m68k-softmmu.mak b/default-configs/devices/m68k-softmmu.mak
index 6629fd2aa330..7f8619e42786 100644
--- a/default-configs/devices/m68k-softmmu.mak
+++ b/default-configs/devices/m68k-softmmu.mak
@@ -8,3 +8,4 @@ CONFIG_AN5206=y
CONFIG_MCF5208=y
CONFIG_NEXTCUBE=y
CONFIG_Q800=y
+CONFIG_M68K_VIRT=y
diff --git a/include/standard-headers/asm-m68k/bootinfo-virt.h b/include/standard-headers/asm-m68k/bootinfo-virt.h
new file mode 100644
index 000000000000..b3d90a601513
--- /dev/null
+++ b/include/standard-headers/asm-m68k/bootinfo-virt.h
@@ -0,0 +1,17 @@
+/* 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 VIRT_BOOTI_VERSION MK_BI_VERSION(2, 0)
+
+#endif /* _UAPI_ASM_M68K_BOOTINFO_MAC_H */
diff --git a/hw/m68k/virt.c b/hw/m68k/virt.c
new file mode 100644
index 000000000000..8b89373dafdb
--- /dev/null
+++ b/hw/m68k/virt.c
@@ -0,0 +1,296 @@
+/*
+ * 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/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 #5
+ * 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 */
+
+/* 1 goldfish-rtc (and timer) */
+#define VIRT_GF_RTC_MMIO_BASE 0xff006000 /* MMIO: 0xff006000 - 0xff006fff */
+#define VIRT_GF_RTC_IRQ_BASE PIC_IRQ(6, 1) /* PIC: #6, IRQ: #1 */
+
+/* 1 goldfish-tty */
+#define VIRT_GF_TTY_MMIO_BASE 0xff007000 /* MMIO: 0xff007000 - 0xff007000 */
+#define VIRT_GF_TTY_IRQ_BASE PIC_IRQ(1, 32) /* PIC: #1, IRQ: #32 */
+/*
+ * 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 */
+
+/*
+ * 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 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 *pic_dev[7];
+ GLUEState *irq;
+ qemu_irq *cpu_pic;
+ 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 Glue */
+
+ irq = g_new0(GLUEState, 1);
+ irq->cpu = cpu;
+ cpu_pic = qemu_allocate_irqs(GLUE_set_irq, irq, 8);
+
+ /*
+ * 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 < 6; i++) {
+ pic_dev[i] = qdev_new(TYPE_GOLDFISH_PIC);
+ sysbus = SYS_BUS_DEVICE(pic_dev[i]);
+ sysbus_realize_and_unref(sysbus, &error_fatal);
+
+ sysbus_mmio_map(sysbus, 0, io_base);
+ sysbus_connect_irq(sysbus, 0, cpu_pic[i]);
+
+ io_base += 0x1000;
+ }
+
+ /* goldfish-rtc */
+ dev = qdev_new(TYPE_GOLDFISH_RTC);
+ sysbus = SYS_BUS_DEVICE(dev);
+ sysbus_realize_and_unref(sysbus, &error_fatal);
+ sysbus_mmio_map(sysbus, 0, VIRT_GF_RTC_MMIO_BASE);
+ sysbus_connect_irq(sysbus, 0, PIC_GPIO(VIRT_GF_RTC_IRQ_BASE));
+
+ /* 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));
+
+ /* 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_MICRO << 16) |
+ (QEMU_VERSION_MINOR << 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_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 = "M68k Virtual Machine";
+ mc->init = virt_init;
+ mc->default_cpu_type = M68K_CPU_TYPE_NAME("m68040");
+ mc->max_cpus = 1;
+ mc->block_default_type = IF_SCSI;
+ mc->default_ram_id = "m68k_virt.ram";
+}
+
+static const TypeInfo virt_machine_typeinfo = {
+ .name = MACHINE_TYPE_NAME("virt"),
+ .parent = TYPE_MACHINE,
+ .class_init = virt_machine_class_init,
+};
+
+static void virt_machine_register_types(void)
+{
+ type_register_static(&virt_machine_typeinfo);
+}
+
+type_init(virt_machine_register_types)
diff --git a/MAINTAINERS b/MAINTAINERS
index d0962a22e1b4..b08cf4251246 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1101,6 +1101,15 @@ 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: include/hw/char/goldfish_tty.h
+F: include/hw/intc/goldfish_pic.h
+
MicroBlaze Machines
-------------------
petalogix_s3adsp1800
diff --git a/hw/m68k/Kconfig b/hw/m68k/Kconfig
index c757e7dfa48b..f4b3b115270e 100644
--- a/hw/m68k/Kconfig
+++ b/hw/m68k/Kconfig
@@ -22,3 +22,11 @@ config Q800
select ESCC
select ESP
select DP8393X
+
+config M68K_VIRT
+ bool
+ select GOLDFISH_PIC
+ select GOLDFISH_TTY
+ select GOLDFISH_RTC
+ select VIRTIO
+ select VIRTIO_MMIO
diff --git a/hw/m68k/meson.build b/hw/m68k/meson.build
index ca0044c652d3..31248641d301 100644
--- a/hw/m68k/meson.build
+++ b/hw/m68k/meson.build
@@ -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}
--
2.26.2
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 4/4] m68k: add Virtual M68k Machine
2020-10-13 15:51 ` [PATCH 4/4] m68k: add Virtual M68k Machine Laurent Vivier
@ 2020-10-13 17:56 ` Philippe Mathieu-Daudé
2020-10-13 19:01 ` Laurent Vivier
0 siblings, 1 reply; 7+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-10-13 17:56 UTC (permalink / raw)
To: Laurent Vivier, qemu-devel
On 10/13/20 5:51 PM, Laurent Vivier wrote:
> The machine is based on Goldfish interfaces defined by Google
> for Android simulator. It uses Goldfish-rtc (timer and RTC),
> Goldfish-pic (PIC) and Goldfish-tty (for serial port and early tty).
>
> The machine is created with 128 virtio-mmio bus, and they can
> be used to use serial console, GPU, disk, NIC, HID, ...
>
> Signed-off-by: Laurent Vivier <laurent@vivier.eu>
> ---
> default-configs/devices/m68k-softmmu.mak | 1 +
> .../standard-headers/asm-m68k/bootinfo-virt.h | 17 +
> hw/m68k/virt.c | 296 ++++++++++++++++++
> MAINTAINERS | 9 +
> hw/m68k/Kconfig | 8 +
> hw/m68k/meson.build | 1 +
> 6 files changed, 332 insertions(+)
> create mode 100644 include/standard-headers/asm-m68k/bootinfo-virt.h
> create mode 100644 hw/m68k/virt.c
>
> diff --git a/default-configs/devices/m68k-softmmu.mak b/default-configs/devices/m68k-softmmu.mak
> index 6629fd2aa330..7f8619e42786 100644
> --- a/default-configs/devices/m68k-softmmu.mak
> +++ b/default-configs/devices/m68k-softmmu.mak
> @@ -8,3 +8,4 @@ CONFIG_AN5206=y
> CONFIG_MCF5208=y
> CONFIG_NEXTCUBE=y
> CONFIG_Q800=y
> +CONFIG_M68K_VIRT=y
> diff --git a/include/standard-headers/asm-m68k/bootinfo-virt.h b/include/standard-headers/asm-m68k/bootinfo-virt.h
> new file mode 100644
> index 000000000000..b3d90a601513
> --- /dev/null
> +++ b/include/standard-headers/asm-m68k/bootinfo-virt.h
> @@ -0,0 +1,17 @@
> +/* 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 VIRT_BOOTI_VERSION MK_BI_VERSION(2, 0)
> +
> +#endif /* _UAPI_ASM_M68K_BOOTINFO_MAC_H */
> diff --git a/hw/m68k/virt.c b/hw/m68k/virt.c
> new file mode 100644
> index 000000000000..8b89373dafdb
> --- /dev/null
> +++ b/hw/m68k/virt.c
> @@ -0,0 +1,296 @@
> +/*
> + * 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/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 #5
> + * 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 */
> +
> +/* 1 goldfish-rtc (and timer) */
> +#define VIRT_GF_RTC_MMIO_BASE 0xff006000 /* MMIO: 0xff006000 - 0xff006fff */
> +#define VIRT_GF_RTC_IRQ_BASE PIC_IRQ(6, 1) /* PIC: #6, IRQ: #1 */
> +
> +/* 1 goldfish-tty */
> +#define VIRT_GF_TTY_MMIO_BASE 0xff007000 /* MMIO: 0xff007000 - 0xff007000 */
> +#define VIRT_GF_TTY_IRQ_BASE PIC_IRQ(1, 32) /* PIC: #1, IRQ: #32 */
> +/*
> + * 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 */
> +
> +/*
> + * 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.
Does your virt machine really requires a GLUE? Or only another
cascaded PIC?
> + */
> +
> +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 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 *pic_dev[7];
> + GLUEState *irq;
> + qemu_irq *cpu_pic;
> + 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));
Due to BOOTINFO1(..., BI_CPUTYPE, CPU_68040) below, don't you
need to check machine->cpu_type == M68K_CPU_TYPE_NAME("m68040")?
> + qemu_register_reset(main_cpu_reset, cpu);
> +
> + /* RAM */
> + memory_region_add_subregion(get_system_memory(), 0, machine->ram);
> +
> + /* IRQ Glue */
> +
> + irq = g_new0(GLUEState, 1);
> + irq->cpu = cpu;
> + cpu_pic = qemu_allocate_irqs(GLUE_set_irq, irq, 8);
> +
> + /*
> + * 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 < 6; i++) {
> + pic_dev[i] = qdev_new(TYPE_GOLDFISH_PIC);
> + sysbus = SYS_BUS_DEVICE(pic_dev[i]);
> + sysbus_realize_and_unref(sysbus, &error_fatal);
> +
> + sysbus_mmio_map(sysbus, 0, io_base);
> + sysbus_connect_irq(sysbus, 0, cpu_pic[i]);
> +
> + io_base += 0x1000;
> + }
> +
> + /* goldfish-rtc */
> + dev = qdev_new(TYPE_GOLDFISH_RTC);
> + sysbus = SYS_BUS_DEVICE(dev);
> + sysbus_realize_and_unref(sysbus, &error_fatal);
> + sysbus_mmio_map(sysbus, 0, VIRT_GF_RTC_MMIO_BASE);
> + sysbus_connect_irq(sysbus, 0, PIC_GPIO(VIRT_GF_RTC_IRQ_BASE));
> +
> + /* 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));
> +
> + /* 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);
(see machine->cpu_type question earlier).
> + 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_MICRO << 16) |
> + (QEMU_VERSION_MINOR << 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_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 = "M68k Virtual Machine";
> + mc->init = virt_init;
> + mc->default_cpu_type = M68K_CPU_TYPE_NAME("m68040");
> + mc->max_cpus = 1;
> + mc->block_default_type = IF_SCSI;
> + mc->default_ram_id = "m68k_virt.ram";
> +}
> +
> +static const TypeInfo virt_machine_typeinfo = {
> + .name = MACHINE_TYPE_NAME("virt"),
> + .parent = TYPE_MACHINE,
> + .class_init = virt_machine_class_init,
> +};
> +
> +static void virt_machine_register_types(void)
> +{
> + type_register_static(&virt_machine_typeinfo);
> +}
> +
> +type_init(virt_machine_register_types)
> diff --git a/MAINTAINERS b/MAINTAINERS
> index d0962a22e1b4..b08cf4251246 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1101,6 +1101,15 @@ F: include/hw/nubus/*
> F: include/hw/display/macfb.h
> F: include/hw/block/swim.h
>
> +virt
Maybe "m68k 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: include/hw/char/goldfish_tty.h
> +F: include/hw/intc/goldfish_pic.h
> +
> MicroBlaze Machines
> -------------------
> petalogix_s3adsp1800
> diff --git a/hw/m68k/Kconfig b/hw/m68k/Kconfig
> index c757e7dfa48b..f4b3b115270e 100644
> --- a/hw/m68k/Kconfig
> +++ b/hw/m68k/Kconfig
> @@ -22,3 +22,11 @@ config Q800
> select ESCC
> select ESP
> select DP8393X
> +
> +config M68K_VIRT
> + bool
> + select GOLDFISH_PIC
> + select GOLDFISH_TTY
> + select GOLDFISH_RTC
> + select VIRTIO
> + select VIRTIO_MMIO
> diff --git a/hw/m68k/meson.build b/hw/m68k/meson.build
> index ca0044c652d3..31248641d301 100644
> --- a/hw/m68k/meson.build
> +++ b/hw/m68k/meson.build
> @@ -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}
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 4/4] m68k: add Virtual M68k Machine
2020-10-13 17:56 ` Philippe Mathieu-Daudé
@ 2020-10-13 19:01 ` Laurent Vivier
0 siblings, 0 replies; 7+ messages in thread
From: Laurent Vivier @ 2020-10-13 19:01 UTC (permalink / raw)
To: Philippe Mathieu-Daudé, qemu-devel
Le 13/10/2020 à 19:56, Philippe Mathieu-Daudé a écrit :
> On 10/13/20 5:51 PM, Laurent Vivier wrote:
>> The machine is based on Goldfish interfaces defined by Google
>> for Android simulator. It uses Goldfish-rtc (timer and RTC),
>> Goldfish-pic (PIC) and Goldfish-tty (for serial port and early tty).
>>
>> The machine is created with 128 virtio-mmio bus, and they can
>> be used to use serial console, GPU, disk, NIC, HID, ...
>>
>> Signed-off-by: Laurent Vivier <laurent@vivier.eu>
>> ---
>> default-configs/devices/m68k-softmmu.mak | 1 +
>> .../standard-headers/asm-m68k/bootinfo-virt.h | 17 +
>> hw/m68k/virt.c | 296 ++++++++++++++++++
>> MAINTAINERS | 9 +
>> hw/m68k/Kconfig | 8 +
>> hw/m68k/meson.build | 1 +
>> 6 files changed, 332 insertions(+)
>> create mode 100644 include/standard-headers/asm-m68k/bootinfo-virt.h
>> create mode 100644 hw/m68k/virt.c
...
>> +/*
>> + * 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.
>
> Does your virt machine really requires a GLUE? Or only another
> cascaded PIC?
I agree code needs cleanup here.
We need something to set the ÌRQ level (priority) and vector (see
m68k_set_irq_level()).
>> + */
>> +
>> +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 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 *pic_dev[7];
>> + GLUEState *irq;
>> + qemu_irq *cpu_pic;
>> + 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));
>
> Due to BOOTINFO1(..., BI_CPUTYPE, CPU_68040) below, don't you
> need to check machine->cpu_type == M68K_CPU_TYPE_NAME("m68040")?
Yes, you're right.
68030MMU is not implemented. So we can't use other CPU than 68040.
>
>> + qemu_register_reset(main_cpu_reset, cpu);
>> +
>> + /* RAM */
>> + memory_region_add_subregion(get_system_memory(), 0, machine->ram);
>> +
>> + /* IRQ Glue */
>> +
>> + irq = g_new0(GLUEState, 1);
>> + irq->cpu = cpu;
>> + cpu_pic = qemu_allocate_irqs(GLUE_set_irq, irq, 8);
>> +
>> + /*
>> + * 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 < 6; i++) {
>> + pic_dev[i] = qdev_new(TYPE_GOLDFISH_PIC);
>> + sysbus = SYS_BUS_DEVICE(pic_dev[i]);
>> + sysbus_realize_and_unref(sysbus, &error_fatal);
>> +
>> + sysbus_mmio_map(sysbus, 0, io_base);
>> + sysbus_connect_irq(sysbus, 0, cpu_pic[i]);
>> +
>> + io_base += 0x1000;
>> + }
>> +
>> + /* goldfish-rtc */
>> + dev = qdev_new(TYPE_GOLDFISH_RTC);
>> + sysbus = SYS_BUS_DEVICE(dev);
>> + sysbus_realize_and_unref(sysbus, &error_fatal);
>> + sysbus_mmio_map(sysbus, 0, VIRT_GF_RTC_MMIO_BASE);
>> + sysbus_connect_irq(sysbus, 0, PIC_GPIO(VIRT_GF_RTC_IRQ_BASE));
>> +
>> + /* 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));
>> +
>> + /* 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);
>
> (see machine->cpu_type question earlier).
see answer above.
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index d0962a22e1b4..b08cf4251246 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -1101,6 +1101,15 @@ F: include/hw/nubus/*
>> F: include/hw/display/macfb.h
>> F: include/hw/block/swim.h
>> +virt
>
> Maybe "m68k virt".
We have "virt" only for ARM, RISCV, Xtensa, ...
the m68k is implied by the qemu-system-m68k
>
>> +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: include/hw/char/goldfish_tty.h
>> +F: include/hw/intc/goldfish_pic.h
>> +
Thanks,
Laurent
^ permalink raw reply [flat|nested] 7+ messages in thread