2021-03-23 22:16:54

by Laurent Vivier

[permalink] [raw]
Subject: [PATCH 0/2] m68k: Add Virtual M68k Machine

The most powerful m68k machine emulated by QEMU is a Quadra 800,

but this machine is very limited: only 1 GiB of memory and only some

specific interfaces, with no DMA.



The Virtual M68k 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 early tty).



The machine is created with 128 virtio-mmio buses, and they can

be used to add serial console, GPU, disk, NIC, HID, hwrng, 9PFS...



The virtual m68k machine has been merged in QEMU and will be available

with the release 6.0.



This series introduces the support of this new machine in the linux kernel.



If you want to try:



- Configure and build latest QEMU with (or download qemu 6.0 binary):



.../configure --target-list=3Dm68k-softmmu --enable-virglrenderer

make



- Configure and build linux with:



make virt_defconfig

make vmlinux



A pre-installed qcow2 disk image is available at:



http://vivier.eu/debian-10.0.qcow2



You can run the machine with something like:



qemu-system-m68k -M virt \

-m 3G \

-chardev stdio,signal=3Doff,mux=3Don,id=3Dchar0 \

-mon chardev=3Dchar0,mode=3Dreadline \

-kernel vmlinux \

-append "console=3Dhvc0 root=3D/dev/vda2" \

-blockdev node-name=3Dsystem,driver=3Dfile,filename=3Ddebian-10.0.qcow2 \

-blockdev node-name=3Ddrive0,driver=3Dqcow2,file=3Dsystem \

-device virtio-blk-device,drive=3Ddrive0 \

-serial chardev:char0 \

-device virtio-net-device,netdev=3Dhostnet0 \

-netdev bridge,id=3Dhostnet0,br=3Dvirbr0,helper=3D/usr/libexec/qemu-bridge-=

helper \

-device virtio-serial-device \

-device virtio-gpu-device \

-device virtconsole,chardev=3Dchar0 \

-device virtio-keyboard-device \

-device virtio-mouse-device



You can watch a presentation about the machine on the Planet m68k channel:



https://youtu.be/s_ve0bCC9q4

[Demo at 38:00]



Thanks,

Laurent



Laurent Vivier (2):

rtc: goldfish: remove dependency to OF

m68k: introduce a virtual m68k machine



arch/m68k/Kbuild | 1 +

arch/m68k/Kconfig.machine | 17 +++

arch/m68k/configs/virt_defconfig | 93 ++++++++++++++++

arch/m68k/include/asm/irq.h | 3 +-

arch/m68k/include/asm/pgtable_mm.h | 7 ++

arch/m68k/include/asm/setup.h | 44 ++++++--

arch/m68k/include/asm/virt.h | 26 +++++

arch/m68k/include/uapi/asm/bootinfo-virt.h | 18 ++++

arch/m68k/include/uapi/asm/bootinfo.h | 1 +

arch/m68k/kernel/Makefile | 1 +

arch/m68k/kernel/head.S | 30 ++++++

arch/m68k/kernel/setup_mm.c | 9 ++

arch/m68k/mm/kmap.c | 20 ++--

arch/m68k/virt/Makefile | 6 ++

arch/m68k/virt/config.c | 118 +++++++++++++++++++++

arch/m68k/virt/ints.c | 110 +++++++++++++++++++

arch/m68k/virt/platform.c | 80 ++++++++++++++

arch/m68k/virt/timer.c | 91 ++++++++++++++++

drivers/rtc/Kconfig | 2 +-

19 files changed, 659 insertions(+), 18 deletions(-)

create mode 100644 arch/m68k/configs/virt_defconfig

create mode 100644 arch/m68k/include/asm/virt.h

create mode 100644 arch/m68k/include/uapi/asm/bootinfo-virt.h

create mode 100644 arch/m68k/virt/Makefile

create mode 100644 arch/m68k/virt/config.c

create mode 100644 arch/m68k/virt/ints.c

create mode 100644 arch/m68k/virt/platform.c

create mode 100644 arch/m68k/virt/timer.c



--=20

2.30.2




2021-03-23 22:18:19

by Laurent Vivier

[permalink] [raw]
Subject: [PATCH 2/2] m68k: introduce a virtual m68k machine

This machine allows to have up to 3.2 GiB and 128 Virtio devices.

It is based on android goldfish devices.

Signed-off-by: Laurent Vivier <[email protected]>
---
arch/m68k/Kbuild | 1 +
arch/m68k/Kconfig.machine | 17 +++
arch/m68k/configs/virt_defconfig | 93 ++++++++++++++++
arch/m68k/include/asm/irq.h | 3 +-
arch/m68k/include/asm/pgtable_mm.h | 7 ++
arch/m68k/include/asm/setup.h | 44 ++++++--
arch/m68k/include/asm/virt.h | 26 +++++
arch/m68k/include/uapi/asm/bootinfo-virt.h | 18 ++++
arch/m68k/include/uapi/asm/bootinfo.h | 1 +
arch/m68k/kernel/Makefile | 1 +
arch/m68k/kernel/head.S | 30 ++++++
arch/m68k/kernel/setup_mm.c | 9 ++
arch/m68k/mm/kmap.c | 20 ++--
arch/m68k/virt/Makefile | 6 ++
arch/m68k/virt/config.c | 118 +++++++++++++++++++++
arch/m68k/virt/ints.c | 110 +++++++++++++++++++
arch/m68k/virt/platform.c | 80 ++++++++++++++
arch/m68k/virt/timer.c | 91 ++++++++++++++++
18 files changed, 658 insertions(+), 17 deletions(-)
create mode 100644 arch/m68k/configs/virt_defconfig
create mode 100644 arch/m68k/include/asm/virt.h
create mode 100644 arch/m68k/include/uapi/asm/bootinfo-virt.h
create mode 100644 arch/m68k/virt/Makefile
create mode 100644 arch/m68k/virt/config.c
create mode 100644 arch/m68k/virt/ints.c
create mode 100644 arch/m68k/virt/platform.c
create mode 100644 arch/m68k/virt/timer.c

diff --git a/arch/m68k/Kbuild b/arch/m68k/Kbuild
index 18abb35c26a1..7762af9f6def 100644
--- a/arch/m68k/Kbuild
+++ b/arch/m68k/Kbuild
@@ -17,3 +17,4 @@ obj-$(CONFIG_M68060) += ifpsp060/
obj-$(CONFIG_M68KFPU_EMU) += math-emu/
obj-$(CONFIG_M68000) += 68000/
obj-$(CONFIG_COLDFIRE) += coldfire/
+obj-$(CONFIG_VIRT) += virt/
diff --git a/arch/m68k/Kconfig.machine b/arch/m68k/Kconfig.machine
index 4d59ec2f5b8d..71d9d7b69ed1 100644
--- a/arch/m68k/Kconfig.machine
+++ b/arch/m68k/Kconfig.machine
@@ -145,6 +145,23 @@ config SUN3

If you don't want to compile a kernel exclusively for a Sun 3, say N.

+config VIRT
+ bool "Virtual M68k Machine support"
+ depends on MMU
+ select MMU_MOTOROLA if MMU
+ select M68040
+ select LEGACY_TIMER_TICK
+ select VIRTIO_MENU
+ select VIRTIO_MMIO
+ select GOLDFISH
+ select TTY
+ select GOLDFISH_TTY
+ select RTC_CLASS
+ select RTC_DRV_GOLDFISH
+ help
+ This options enable a pure virtual machine based on m68k,
+ VIRTIO MMIO devices and GOLDFISH interfaces (TTY, RTC, PIC)
+
config PILOT
bool

diff --git a/arch/m68k/configs/virt_defconfig b/arch/m68k/configs/virt_defconfig
new file mode 100644
index 000000000000..51842acd5434
--- /dev/null
+++ b/arch/m68k/configs/virt_defconfig
@@ -0,0 +1,93 @@
+CONFIG_M68K=y
+CONFIG_M68040=y
+CONFIG_VIRT=y
+CONFIG_DEVTMPFS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_TMPFS_XATTR=y
+CONFIG_UNIX=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_AUTOFS_FS=y
+CONFIG_SYSFS=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_SYSCTL=y
+CONFIG_SGETMASK_SYSCALL=y
+CONFIG_SYSFS_SYSCALL=y
+CONFIG_ADVISE_SYSCALLS=y
+CONFIG_EXT4_FS=y
+CONFIG_SHMEM=y
+CONFIG_CGROUPS=y
+CONFIG_BLK_CGROUP=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_CGROUP_PIDS=y
+CONFIG_CGROUP_RDMA=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_NET_PRIO=y
+CONFIG_CGROUP_NET_CLASSID=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_AMIGA_PARTITION=y
+CONFIG_ATARI_PARTITION=y
+CONFIG_MAC_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+CONFIG_LDM_PARTITION=y
+CONFIG_LDM_DEBUG=y
+CONFIG_SUN_PARTITION=y
+CONFIG_EFI_PARTITION=y
+CONFIG_SYSV68_PARTITION=y
+CONFIG_BLK_MQ_VIRTIO=y
+CONFIG_INET=y
+CONFIG_PACKET=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_NETDEVICES=y
+CONFIG_NET=y
+CONFIG_NET_CORE=y
+CONFIG_NET_9P=y
+CONFIG_NET_9P_VIRTIO=y
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_ETHTOOL_NETLINK=y
+CONFIG_9P_FS=y
+CONFIG_9P_FS_POSIX_ACL=y
+CONFIG_9P_FS_SECURITY=y
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=y
+CONFIG_BLOCK=y
+CONFIG_BLK_DEV=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_VIRTIO_BLK=y
+CONFIG_SCSI=y
+CONFIG_SCSI_LOWLEVEL=y
+CONFIG_SCSI_VIRTIO=y
+CONFIG_VIRTIO_NET=y
+CONFIG_GOLDFISH_TTY=y
+CONFIG_GOLDFISH_TTY_EARLY_CONSOLE=y
+CONFIG_VIRTIO_CONSOLE=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_VIRTIO=y
+CONFIG_DRM=y
+CONFIG_DRM_VIRTIO_GPU=y
+CONFIG_VIRT_DRIVERS=y
+CONFIG_VIRTIO=y
+CONFIG_VIRTIO_MENU=y
+CONFIG_VIRTIO_INPUT=y
+CONFIG_VIRTIO_MMIO=y
+CONFIG_VIRTIO_DMA_SHARED_BUFFER=y
+CONFIG_GOLDFISH=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_INPUT=y
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_PROC_HARDWARE=y
diff --git a/arch/m68k/include/asm/irq.h b/arch/m68k/include/asm/irq.h
index 91dd493791d7..7829e955ca04 100644
--- a/arch/m68k/include/asm/irq.h
+++ b/arch/m68k/include/asm/irq.h
@@ -12,7 +12,8 @@
*/
#if defined(CONFIG_COLDFIRE)
#define NR_IRQS 256
-#elif defined(CONFIG_VME) || defined(CONFIG_SUN3) || defined(CONFIG_SUN3X)
+#elif defined(CONFIG_VME) || defined(CONFIG_SUN3) || \
+ defined(CONFIG_SUN3X) || defined(CONFIG_VIRT)
#define NR_IRQS 200
#elif defined(CONFIG_ATARI)
#define NR_IRQS 141
diff --git a/arch/m68k/include/asm/pgtable_mm.h b/arch/m68k/include/asm/pgtable_mm.h
index aca22c2c1ee2..8b9279971ff6 100644
--- a/arch/m68k/include/asm/pgtable_mm.h
+++ b/arch/m68k/include/asm/pgtable_mm.h
@@ -81,6 +81,9 @@
#elif defined(CONFIG_COLDFIRE)
#define KMAP_START 0xe0000000
#define KMAP_END 0xf0000000
+#elif defined(CONFIG_VIRT)
+#define KMAP_START 0xdf000000
+#define KMAP_END 0xff000000
#else
#define KMAP_START 0xd0000000
#define KMAP_END 0xf0000000
@@ -93,6 +96,10 @@ extern unsigned long m68k_vmalloc_end;
#elif defined(CONFIG_COLDFIRE)
#define VMALLOC_START 0xd0000000
#define VMALLOC_END 0xe0000000
+#elif defined(CONFIG_VIRT)
+#define VMALLOC_OFFSET PAGE_SIZE
+#define VMALLOC_START (((unsigned long) high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+#define VMALLOC_END KMAP_START
#else
/* Just any arbitrary offset to the start of the vmalloc VM area: the
* current 8MB value just means that there will be a 8MB "hole" after the
diff --git a/arch/m68k/include/asm/setup.h b/arch/m68k/include/asm/setup.h
index 8f2023f8c1c4..20de7f30f484 100644
--- a/arch/m68k/include/asm/setup.h
+++ b/arch/m68k/include/asm/setup.h
@@ -37,7 +37,8 @@ extern unsigned long m68k_machtype;
#elif defined(CONFIG_ATARI) || defined(CONFIG_MAC) || defined(CONFIG_APOLLO) \
|| defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000) \
|| defined(CONFIG_HP300) || defined(CONFIG_Q40) \
- || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
+ || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147) \
+ || defined(CONFIG_VIRT)
# define MACH_IS_AMIGA (m68k_machtype == MACH_AMIGA)
#else
# define MACH_AMIGA_ONLY
@@ -50,7 +51,8 @@ extern unsigned long m68k_machtype;
#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_APOLLO) \
|| defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000) \
|| defined(CONFIG_HP300) || defined(CONFIG_Q40) \
- || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
+ || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147) \
+ || defined(CONFIG_VIRT)
# define MACH_IS_ATARI (m68k_machtype == MACH_ATARI)
#else
# define MACH_ATARI_ONLY
@@ -63,7 +65,8 @@ extern unsigned long m68k_machtype;
#elif defined(CONFIG_AMIGA) || defined(CONFIG_ATARI) || defined(CONFIG_APOLLO) \
|| defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000) \
|| defined(CONFIG_HP300) || defined(CONFIG_Q40) \
- || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
+ || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147) \
+ || defined(CONFIG_VIRT)
# define MACH_IS_MAC (m68k_machtype == MACH_MAC)
#else
# define MACH_MAC_ONLY
@@ -84,7 +87,8 @@ extern unsigned long m68k_machtype;
#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
|| defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000) \
|| defined(CONFIG_HP300) || defined(CONFIG_Q40) \
- || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
+ || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147) \
+ || defined(CONFIG_VIRT)
# define MACH_IS_APOLLO (m68k_machtype == MACH_APOLLO)
#else
# define MACH_APOLLO_ONLY
@@ -97,7 +101,8 @@ extern unsigned long m68k_machtype;
#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
|| defined(CONFIG_APOLLO) || defined(CONFIG_BVME6000) \
|| defined(CONFIG_HP300) || defined(CONFIG_Q40) \
- || defined(CONFIG_SUN3X) || defined(CONFIG_MVME16x)
+ || defined(CONFIG_SUN3X) || defined(CONFIG_MVME16x) \
+ || defined(CONFIG_VIRT)
# define MACH_IS_MVME147 (m68k_machtype == MACH_MVME147)
#else
# define MACH_MVME147_ONLY
@@ -110,7 +115,8 @@ extern unsigned long m68k_machtype;
#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
|| defined(CONFIG_APOLLO) || defined(CONFIG_BVME6000) \
|| defined(CONFIG_HP300) || defined(CONFIG_Q40) \
- || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
+ || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147) \
+ || defined(CONFIG_VIRT)
# define MACH_IS_MVME16x (m68k_machtype == MACH_MVME16x)
#else
# define MACH_MVME16x_ONLY
@@ -123,7 +129,8 @@ extern unsigned long m68k_machtype;
#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
|| defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x) \
|| defined(CONFIG_HP300) || defined(CONFIG_Q40) \
- || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
+ || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147) \
+ || defined(CONFIG_VIRT)
# define MACH_IS_BVME6000 (m68k_machtype == MACH_BVME6000)
#else
# define MACH_BVME6000_ONLY
@@ -136,7 +143,8 @@ extern unsigned long m68k_machtype;
#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
|| defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x) \
|| defined(CONFIG_BVME6000) || defined(CONFIG_Q40) \
- || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
+ || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147) \
+ || defined(CONFIG_VIRT)
# define MACH_IS_HP300 (m68k_machtype == MACH_HP300)
#else
# define MACH_HP300_ONLY
@@ -149,7 +157,8 @@ extern unsigned long m68k_machtype;
#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
|| defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x) \
|| defined(CONFIG_BVME6000) || defined(CONFIG_HP300) \
- || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147)
+ || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147) \
+ || defined(CONFIG_VIRT)
# define MACH_IS_Q40 (m68k_machtype == MACH_Q40)
#else
# define MACH_Q40_ONLY
@@ -162,7 +171,8 @@ extern unsigned long m68k_machtype;
#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
|| defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x) \
|| defined(CONFIG_BVME6000) || defined(CONFIG_HP300) \
- || defined(CONFIG_Q40) || defined(CONFIG_MVME147)
+ || defined(CONFIG_Q40) || defined(CONFIG_MVME147) \
+ || defined(CONFIG_VIRT)
# define MACH_IS_SUN3X (m68k_machtype == MACH_SUN3X)
#else
# define CONFIG_SUN3X_ONLY
@@ -170,6 +180,20 @@ extern unsigned long m68k_machtype;
# define MACH_TYPE (MACH_SUN3X)
#endif

+#if !defined(CONFIG_VIRT)
+# define MACH_IS_VIRT (0)
+#elif defined(CONFIG_AMIGA) || defined(CONFIG_ATARI) || defined(CONFIG_APOLLO) \
+ || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000) \
+ || defined(CONFIG_HP300) || defined(CONFIG_Q40) \
+ || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147) \
+ || defined(CONFIG_MAC)
+# define MACH_IS_VIRT (m68k_machtype == MACH_VIRT)
+#else
+# define MACH_VIRTONLY
+# define MACH_IS_VIRT (1)
+# define MACH_TYPE (MACH_VIRT)
+#endif
+
#ifndef MACH_TYPE
# define MACH_TYPE (m68k_machtype)
#endif
diff --git a/arch/m68k/include/asm/virt.h b/arch/m68k/include/asm/virt.h
new file mode 100644
index 000000000000..2795a70f709b
--- /dev/null
+++ b/arch/m68k/include/asm/virt.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_VIRT_H
+#define __ASM_VIRT_H
+
+#define NUM_VIRT_SOURCES 200
+
+struct virt_booter_device_data {
+ unsigned long mmio;
+ unsigned long irq;
+};
+
+struct virt_booter_data {
+ unsigned long qemu_version;
+ struct virt_booter_device_data pic;
+ struct virt_booter_device_data rtc;
+ struct virt_booter_device_data tty;
+ struct virt_booter_device_data ctrl;
+ struct virt_booter_device_data virtio;
+};
+
+extern struct virt_booter_data virt_bi_data;
+
+extern void __init virt_init_IRQ(void);
+extern void __init virt_sched_init(void);
+
+#endif
diff --git a/arch/m68k/include/uapi/asm/bootinfo-virt.h b/arch/m68k/include/uapi/asm/bootinfo-virt.h
new file mode 100644
index 000000000000..ab17fd9d200d
--- /dev/null
+++ b/arch/m68k/include/uapi/asm/bootinfo-virt.h
@@ -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 */
diff --git a/arch/m68k/include/uapi/asm/bootinfo.h b/arch/m68k/include/uapi/asm/bootinfo.h
index 38d3140381fa..203d9cbf9630 100644
--- a/arch/m68k/include/uapi/asm/bootinfo.h
+++ b/arch/m68k/include/uapi/asm/bootinfo.h
@@ -83,6 +83,7 @@ struct mem_info {
#define MACH_SUN3X 11
#define MACH_M54XX 12
#define MACH_M5441X 13
+#define MACH_VIRT 14


/*
diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile
index dbac7f8743fc..c0833da6a2ca 100644
--- a/arch/m68k/kernel/Makefile
+++ b/arch/m68k/kernel/Makefile
@@ -11,6 +11,7 @@ extra-$(CONFIG_VME) := head.o
extra-$(CONFIG_HP300) := head.o
extra-$(CONFIG_Q40) := head.o
extra-$(CONFIG_SUN3X) := head.o
+extra-$(CONFIG_VIRT) := head.o
extra-$(CONFIG_SUN3) := sun3-head.o
extra-y += vmlinux.lds

diff --git a/arch/m68k/kernel/head.S b/arch/m68k/kernel/head.S
index 493c95db0e51..d4a4bbecf6c0 100644
--- a/arch/m68k/kernel/head.S
+++ b/arch/m68k/kernel/head.S
@@ -262,6 +262,7 @@
#include <asm/bootinfo-hp300.h>
#include <asm/bootinfo-mac.h>
#include <asm/bootinfo-q40.h>
+#include <asm/bootinfo-virt.h>
#include <asm/bootinfo-vme.h>
#include <asm/setup.h>
#include <asm/entry.h>
@@ -534,6 +535,7 @@ func_define putn,1
#define is_not_apollo(lab) cmpl &MACH_APOLLO,%pc@(m68k_machtype); jne lab
#define is_not_q40(lab) cmpl &MACH_Q40,%pc@(m68k_machtype); jne lab
#define is_not_sun3x(lab) cmpl &MACH_SUN3X,%pc@(m68k_machtype); jne lab
+#define is_not_virt(lab) cmpl &MACH_VIRT,%pc@(m68k_machtype); jne lab

#define hasnt_leds(lab) cmpl &MACH_HP300,%pc@(m68k_machtype); \
jeq 42f; \
@@ -647,6 +649,14 @@ ENTRY(__start)
L(test_notmac):
#endif /* CONFIG_MAC */

+#ifdef CONFIG_VIRT
+ is_not_virt(L(test_notvirt))
+
+ get_bi_record BI_VIRT_GF_TTY_BASE
+ lea %pc@(L(virt_gf_tty_base)),%a1
+ movel %a0@,%a1@
+L(test_notvirt):
+#endif /* CONFIG_VIRT */

/*
* There are ultimately two pieces of information we want for all kinds of
@@ -1237,6 +1247,13 @@ L(mmu_init_not_mac):
L(notsun3x):
#endif

+#ifdef CONFIG_VIRT
+ is_not_virt(L(novirt))
+ mmu_map_tt #1,#0xFF000000,#0x01000000,#_PAGE_NOCACHE_S
+ jbra L(mmu_init_done)
+L(novirt):
+#endif
+
#ifdef CONFIG_APOLLO
is_not_apollo(L(notapollo))

@@ -3186,6 +3203,13 @@ func_start serial_putc,%d0/%d1/%a0/%a1
3:
#endif

+#ifdef CONFIG_VIRT
+ is_not_virt(L(serial_putc_done))
+
+ movel L(virt_gf_tty_base),%a1
+ moveb %d0,%a1@(GF_PUT_CHAR)
+#endif
+
L(serial_putc_done):
func_return serial_putc

@@ -3865,3 +3889,9 @@ q40_mem_cptr:
L(q40_do_debug):
.long 0
#endif
+
+#if defined(CONFIG_VIRT)
+GF_PUT_CHAR = 0x00
+L(virt_gf_tty_base):
+ .long 0
+#endif /* CONFIG_VIRT */
diff --git a/arch/m68k/kernel/setup_mm.c b/arch/m68k/kernel/setup_mm.c
index 017bac3aab80..b628d0a1f3f1 100644
--- a/arch/m68k/kernel/setup_mm.c
+++ b/arch/m68k/kernel/setup_mm.c
@@ -122,6 +122,7 @@ extern int mvme16x_parse_bootinfo(const struct bi_record *);
extern int mvme147_parse_bootinfo(const struct bi_record *);
extern int hp300_parse_bootinfo(const struct bi_record *);
extern int apollo_parse_bootinfo(const struct bi_record *);
+extern int virt_parse_bootinfo(const struct bi_record *);

extern void config_amiga(void);
extern void config_atari(void);
@@ -134,6 +135,7 @@ extern void config_bvme6000(void);
extern void config_hp300(void);
extern void config_q40(void);
extern void config_sun3x(void);
+extern void config_virt(void);

#define MASK_256K 0xfffc0000

@@ -203,6 +205,8 @@ static void __init m68k_parse_bootinfo(const struct bi_record *record)
unknown = hp300_parse_bootinfo(record);
else if (MACH_IS_APOLLO)
unknown = apollo_parse_bootinfo(record);
+ else if (MACH_IS_VIRT)
+ unknown = virt_parse_bootinfo(record);
else
unknown = 1;
}
@@ -336,6 +340,11 @@ void __init setup_arch(char **cmdline_p)
cf_mmu_context_init();
config_BSP(NULL, 0);
break;
+#endif
+#ifdef CONFIG_VIRT
+ case MACH_VIRT:
+ config_virt();
+ break;
#endif
default:
panic("No configuration setup");
diff --git a/arch/m68k/mm/kmap.c b/arch/m68k/mm/kmap.c
index 1269d513b221..41c72f50c0a2 100644
--- a/arch/m68k/mm/kmap.c
+++ b/arch/m68k/mm/kmap.c
@@ -180,6 +180,12 @@ void __iomem *__ioremap(unsigned long physaddr, unsigned long size, int cachefla
return (void __iomem *)physaddr;
}
#endif
+#ifdef CONFIG_VIRT
+ if (MACH_IS_VIRT) {
+ if (physaddr >= 0xff000000 && cacheflag == IOMAP_NOCACHE_SER)
+ return (void __iomem *)physaddr;
+ }
+#endif
#ifdef CONFIG_COLDFIRE
if (__cf_internalio(physaddr))
return (void __iomem *) physaddr;
@@ -293,18 +299,20 @@ EXPORT_SYMBOL(__ioremap);
*/
void iounmap(void __iomem *addr)
{
-#ifdef CONFIG_AMIGA
- if ((!MACH_IS_AMIGA) ||
- (((unsigned long)addr < 0x40000000) ||
- ((unsigned long)addr > 0x60000000)))
- free_io_area((__force void *)addr);
+#if defined(CONFIG_AMIGA) || defined(CONFIG_VIRT)
+ if (MACH_IS_AMIGA &&
+ ((unsigned long)addr >= 0x40000000) &&
+ ((unsigned long)addr < 0x60000000))
+ return;
+ if (MACH_IS_VIRT && (unsigned long)addr >= 0xff000000)
+ return;
#else
#ifdef CONFIG_COLDFIRE
if (cf_internalio(addr))
return;
#endif
- free_io_area((__force void *)addr);
#endif
+ free_io_area((__force void *)addr);
}
EXPORT_SYMBOL(iounmap);

diff --git a/arch/m68k/virt/Makefile b/arch/m68k/virt/Makefile
new file mode 100644
index 000000000000..40420fc886bb
--- /dev/null
+++ b/arch/m68k/virt/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Makefile for Linux arch/m68k/virt source directory
+#
+
+obj-y := config.o ints.o platform.o timer.o
diff --git a/arch/m68k/virt/config.c b/arch/m68k/virt/config.c
new file mode 100644
index 000000000000..ea22eed73a90
--- /dev/null
+++ b/arch/m68k/virt/config.c
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/serial_core.h>
+
+#include <asm/bootinfo.h>
+#include <asm/bootinfo-virt.h>
+#include <asm/byteorder.h>
+
+#include <asm/machdep.h>
+#include <asm/virt.h>
+
+struct virt_booter_data virt_bi_data;
+
+struct virt_ctrl {
+ u32 features;
+ u32 cmd;
+};
+
+enum {
+ CMD_NOOP,
+ CMD_RESET,
+ CMD_HALT,
+ CMD_PANIC,
+};
+
+#define virt_ctrl ((volatile struct virt_ctrl *)virt_bi_data.ctrl.mmio)
+
+static void virt_get_model(char *str)
+{
+ /* str is 80 characters long */
+ sprintf(str, "QEMU Virtual M68K Machine (%d.%d.%d)",
+ (u8)(virt_bi_data.qemu_version >> 24),
+ (u8)(virt_bi_data.qemu_version >> 16),
+ (u8)(virt_bi_data.qemu_version >> 8));
+}
+
+extern void show_registers(struct pt_regs *);
+
+static void virt_halt(void)
+{
+ virt_ctrl->cmd = CMD_HALT;
+ local_irq_disable();
+ while (1)
+ ;
+}
+
+static void virt_reset(void)
+{
+ virt_ctrl->cmd = CMD_RESET;
+ local_irq_disable();
+ while (1)
+ ;
+}
+
+/*
+ * Parse a virtual-m68k-specific record in the bootinfo
+ */
+
+int __init virt_parse_bootinfo(const struct bi_record *record)
+{
+ int unknown = 0;
+ const void *data = record->data;
+
+ switch (be16_to_cpu(record->tag)) {
+ case BI_VIRT_QEMU_VERSION:
+ virt_bi_data.qemu_version = be32_to_cpup(data);
+ break;
+ case BI_VIRT_GF_PIC_BASE:
+ virt_bi_data.pic.mmio = be32_to_cpup(data);
+ data += 4;
+ virt_bi_data.pic.irq = be32_to_cpup(data);
+ break;
+ case BI_VIRT_GF_RTC_BASE:
+ virt_bi_data.rtc.mmio = be32_to_cpup(data);
+ data += 4;
+ virt_bi_data.rtc.irq = be32_to_cpup(data);
+ break;
+ case BI_VIRT_GF_TTY_BASE:
+ virt_bi_data.tty.mmio = be32_to_cpup(data);
+ data += 4;
+ virt_bi_data.tty.irq = be32_to_cpup(data);
+ break;
+ case BI_VIRT_CTRL_BASE:
+ virt_bi_data.ctrl.mmio = be32_to_cpup(data);
+ data += 4;
+ virt_bi_data.ctrl.irq = be32_to_cpup(data);
+ break;
+ case BI_VIRT_VIRTIO_BASE:
+ virt_bi_data.virtio.mmio = be32_to_cpup(data);
+ data += 4;
+ virt_bi_data.virtio.irq = be32_to_cpup(data);
+ break;
+ default:
+ unknown = 1;
+ break;
+ }
+ return unknown;
+}
+
+void __init config_virt(void)
+{
+ char earlycon[24];
+
+ if (!MACH_IS_VIRT)
+ pr_err("ERROR: no Virtual M68k Machine, but %s called!!\n",
+ __func__);
+
+ snprintf(earlycon, sizeof(earlycon), "early_gf_tty,0x%08lx",
+ virt_bi_data.tty.mmio);
+ setup_earlycon(earlycon);
+
+ mach_init_IRQ = virt_init_IRQ;
+ mach_sched_init = virt_sched_init;
+ mach_get_model = virt_get_model;
+ mach_reset = virt_reset;
+ mach_halt = virt_halt;
+ mach_power_off = virt_halt;
+}
diff --git a/arch/m68k/virt/ints.c b/arch/m68k/virt/ints.c
new file mode 100644
index 000000000000..aa94cb3b6d96
--- /dev/null
+++ b/arch/m68k/virt/ints.c
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/sched/debug.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+
+#include <asm/virt.h>
+#include <asm/irq.h>
+#include <asm/hwtest.h>
+#include <asm/irq_regs.h>
+
+struct goldfish_pic {
+ u32 status;
+ u32 irq_pending;
+ u32 irq_diable_all;
+ u32 disable;
+ u32 enable;
+ u32 pad[1019];
+};
+
+extern void show_registers(struct pt_regs *);
+
+#define gf_pic ((volatile struct goldfish_pic *)virt_bi_data.pic.mmio)
+
+#define GF_PIC(irq) (gf_pic[(irq - IRQ_USER) / 32])
+#define GF_IRQ(irq) ((irq - IRQ_USER) % 32)
+
+static void virt_irq_enable(struct irq_data *data)
+{
+ GF_PIC(data->irq).enable = 1 << GF_IRQ(data->irq);
+}
+
+static void virt_irq_disable(struct irq_data *data)
+{
+ GF_PIC(data->irq).disable = 1 << GF_IRQ(data->irq);
+}
+
+static unsigned int virt_irq_startup(struct irq_data *data)
+{
+ GF_PIC(data->irq).enable = 1 << GF_IRQ(data->irq);
+ return 0;
+}
+
+static void virt_irq_shutdown(struct irq_data *data)
+{
+ GF_PIC(data->irq).disable = 1 << GF_IRQ(data->irq);
+}
+
+static volatile int in_nmi;
+
+irqreturn_t virt_nmi_handler(int irq, void *dev_id)
+{
+ if (in_nmi)
+ return IRQ_HANDLED;
+ in_nmi = 1;
+
+ pr_info("Non-Maskable Interrupt\n");
+ show_registers(get_irq_regs());
+
+ in_nmi = 0;
+ return IRQ_HANDLED;
+}
+
+static struct irq_chip virt_irq_chip = {
+ .name = "virt",
+ .irq_enable = virt_irq_enable,
+ .irq_disable = virt_irq_disable,
+ .irq_startup = virt_irq_startup,
+ .irq_shutdown = virt_irq_shutdown,
+};
+
+static void goldfish_pic_irq(struct irq_desc *desc)
+{
+ u32 irq_pending, irq_bit;
+ int irq_num;
+
+ irq_pending = gf_pic[desc->irq_data.irq - 1].irq_pending;
+ irq_num = IRQ_USER + (desc->irq_data.irq - 1) * 32;
+ irq_bit = 1;
+
+ do {
+ if (irq_pending & irq_bit) {
+ generic_handle_irq(irq_num);
+ irq_pending &= ~irq_bit;
+ }
+ ++irq_num;
+ irq_bit <<= 1;
+ } while (irq_pending);
+}
+
+void __init virt_init_IRQ(void)
+{
+ int i;
+
+ m68k_setup_irq_controller(&virt_irq_chip, handle_simple_irq, IRQ_USER,
+ NUM_VIRT_SOURCES - IRQ_USER);
+
+ for (i = 0; i < 6; i++) {
+ irq_set_chained_handler(virt_bi_data.pic.irq + i,
+ goldfish_pic_irq);
+ }
+
+ if (request_irq(IRQ_AUTO_7, virt_nmi_handler, 0, "NMI",
+ virt_nmi_handler))
+ pr_err("Couldn't register NMI\n");
+}
diff --git a/arch/m68k/virt/platform.c b/arch/m68k/virt/platform.c
new file mode 100644
index 000000000000..311d53dec487
--- /dev/null
+++ b/arch/m68k/virt/platform.c
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <asm/virt.h>
+#include <asm/irq.h>
+
+static struct platform_device virt_m68k_goldfish_tty = {
+ .name = "goldfish_tty",
+ .id = PLATFORM_DEVID_NONE,
+ .num_resources = 2,
+ .resource = (struct resource [2]) { },
+};
+static struct platform_device virt_m68k_goldfish_rtc = {
+ .name = "goldfish_rtc",
+ .id = PLATFORM_DEVID_NONE,
+ .num_resources = 2,
+ .resource = (struct resource [2]) { },
+};
+
+#define VIRTIO_BUS_NB 128
+static struct platform_device virt_m68k_virtio_mmio_device[VIRTIO_BUS_NB];
+static struct resource virt_m68k_virtio_mmio_resources[VIRTIO_BUS_NB][2];
+
+static int __init virt_platform_init(void)
+{
+ int err;
+ int i;
+ extern unsigned long min_low_pfn;
+
+ if (!MACH_IS_VIRT)
+ return -ENODEV;
+
+ min_low_pfn = 0;
+
+ virt_m68k_goldfish_tty.resource[0].flags = IORESOURCE_MEM;
+ virt_m68k_goldfish_tty.resource[0].start = virt_bi_data.tty.mmio;
+ virt_m68k_goldfish_tty.resource[0].end = virt_bi_data.tty.mmio;
+ virt_m68k_goldfish_tty.resource[1].flags = IORESOURCE_IRQ;
+ virt_m68k_goldfish_tty.resource[1].start = virt_bi_data.tty.irq;
+ virt_m68k_goldfish_tty.resource[1].end = virt_bi_data.tty.irq;
+
+ err = platform_device_register(&virt_m68k_goldfish_tty);
+ if (err)
+ return err;
+
+ virt_m68k_goldfish_rtc.resource[0].flags = IORESOURCE_MEM;
+ virt_m68k_goldfish_rtc.resource[0].start = virt_bi_data.rtc.mmio + 0x1000;
+ virt_m68k_goldfish_rtc.resource[0].end = virt_bi_data.rtc.mmio + 0x1fff;
+ virt_m68k_goldfish_rtc.resource[1].flags = IORESOURCE_IRQ;
+ virt_m68k_goldfish_rtc.resource[1].start = virt_bi_data.rtc.irq + 1;
+ virt_m68k_goldfish_rtc.resource[1].end = virt_bi_data.rtc.irq + 1;
+ err = platform_device_register(&virt_m68k_goldfish_rtc);
+ if (err)
+ return err;
+
+ for (i = 0; i < VIRTIO_BUS_NB; i++) {
+ virt_m68k_virtio_mmio_device[i].name = "virtio-mmio";
+ virt_m68k_virtio_mmio_device[i].id = i;
+ virt_m68k_virtio_mmio_device[i].num_resources = 2;
+ virt_m68k_virtio_mmio_device[i].resource = virt_m68k_virtio_mmio_resources[i];
+
+ virt_m68k_virtio_mmio_resources[i][0].flags = IORESOURCE_MEM;
+ virt_m68k_virtio_mmio_resources[i][0].start = virt_bi_data.virtio.mmio +
+ i * 0x200;
+ virt_m68k_virtio_mmio_resources[i][0].end = virt_bi_data.virtio.mmio +
+ (i + 1) * 0x200 - 1;
+ virt_m68k_virtio_mmio_resources[i][1].flags = IORESOURCE_IRQ;
+ virt_m68k_virtio_mmio_resources[i][1].start = virt_bi_data.virtio.irq + i;
+ virt_m68k_virtio_mmio_resources[i][1].end = virt_bi_data.virtio.irq + i;
+
+ err = platform_device_register(&virt_m68k_virtio_mmio_device[i]);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+arch_initcall(virt_platform_init);
diff --git a/arch/m68k/virt/timer.c b/arch/m68k/virt/timer.c
new file mode 100644
index 000000000000..705fd53beac5
--- /dev/null
+++ b/arch/m68k/virt/timer.c
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/clocksource.h>
+#include <asm/virt.h>
+
+struct goldfish_timer {
+ u32 time_low;
+ u32 time_high;
+ u32 alarm_low;
+ u32 alarm_high;
+ u32 irq_enabled;
+ u32 clear_alarm;
+ u32 alarm_status;
+ u32 clear_interrupt;
+};
+
+#define gf_timer ((volatile struct goldfish_timer *)virt_bi_data.rtc.mmio)
+
+static u64 goldfish_timer_read(struct clocksource *cs)
+{
+ u64 ticks;
+
+ ticks = gf_timer->time_low;
+ ticks += (u64)gf_timer->time_high << 32;
+
+ return ticks;
+}
+
+static struct clocksource goldfish_timer = {
+ .name = "goldfish_timer",
+ .rating = 400,
+ .read = goldfish_timer_read,
+ .mask = CLOCKSOURCE_MASK(64),
+ .flags = 0,
+ .max_idle_ns = LONG_MAX,
+};
+
+static irqreturn_t golfish_timer_handler(int irq, void *dev_id)
+{
+ unsigned long flags;
+ u64 now;
+
+ local_irq_save(flags);
+ gf_timer->clear_interrupt = 1;
+
+ now = gf_timer->time_low;
+ now += (u64)gf_timer->time_high << 32;
+
+ legacy_timer_tick(1);
+
+ now += NSEC_PER_SEC / HZ;
+ gf_timer->alarm_high = now >> 32;
+ gf_timer->alarm_low = (u32)now;
+ local_irq_restore(flags);
+
+ return IRQ_HANDLED;
+}
+
+void __init virt_sched_init(void)
+{
+ u64 now;
+ static struct resource sched_res;
+
+ sched_res.name = "goldfish_timer";
+ sched_res.start = virt_bi_data.rtc.mmio;
+ sched_res.end = virt_bi_data.rtc.mmio + 0xfff;
+
+ if (request_resource(&iomem_resource, &sched_res)) {
+ pr_err("Cannot allocate goldfish-timer resource\n");
+ return;
+ }
+
+ if (request_irq(virt_bi_data.rtc.irq, golfish_timer_handler, IRQF_TIMER,
+ "timer", NULL)) {
+ pr_err("Couldn't register timer interrupt\n");
+ return;
+ }
+
+ now = gf_timer->time_low;
+ now += (u64)gf_timer->time_high << 32;
+ now += NSEC_PER_SEC / HZ;
+
+ gf_timer->clear_interrupt = 1;
+ gf_timer->alarm_high = now >> 32;
+ gf_timer->alarm_low = (u32)now;
+ gf_timer->irq_enabled = 1;
+
+ clocksource_register_hz(&goldfish_timer, NSEC_PER_SEC);
+}
--
2.30.2

2021-03-23 22:18:54

by Laurent Vivier

[permalink] [raw]
Subject: [PATCH 1/2] rtc: goldfish: remove dependency to OF

We want to use the goldfish RTC on a machine without OF.
As there is no real dependency on it, remove the OF dependency from the
goldfish entry in Kconfig

Signed-off-by: Laurent Vivier <[email protected]>
---
drivers/rtc/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index ce723dc54aa4..5a35ddddd8c6 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1898,7 +1898,7 @@ config RTC_DRV_HID_SENSOR_TIME

config RTC_DRV_GOLDFISH
tristate "Goldfish Real Time Clock"
- depends on OF && HAS_IOMEM
+ depends on HAS_IOMEM
help
Say yes to enable RTC driver for the Goldfish based virtual platform.

--
2.30.2

2021-04-16 22:00:04

by Alexandre Belloni

[permalink] [raw]
Subject: Re: [PATCH 0/2] m68k: Add Virtual M68k Machine

On Tue, 23 Mar 2021 23:14:28 +0100, Laurent Vivier wrote:
> The most powerful m68k machine emulated by QEMU is a Quadra 800,
> but this machine is very limited: only 1 GiB of memory and only some
> specific interfaces, with no DMA.
>
> The Virtual M68k 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 early tty).
>
> [...]

Applied, thanks!

[1/2] rtc: goldfish: remove dependency to OF
commit: 3fd00fdc4f11c656a63e6a6280c0bcb63cf109a2
[2/2] m68k: introduce a virtual m68k machine
commit: 95631785c64840f3816f7a4cc2ce1a5332f43184

Best regards,
--
Alexandre Belloni <[email protected]>

2021-04-16 22:00:46

by Alexandre Belloni

[permalink] [raw]
Subject: Re: [PATCH 0/2] m68k: Add Virtual M68k Machine

On 16/04/2021 22:26:26+0200, Alexandre Belloni wrote:
> On Tue, 23 Mar 2021 23:14:28 +0100, Laurent Vivier wrote:
> > The most powerful m68k machine emulated by QEMU is a Quadra 800,
> > but this machine is very limited: only 1 GiB of memory and only some
> > specific interfaces, with no DMA.
> >
> > The Virtual M68k 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 early tty).
> >
> > [...]
>
> Applied, thanks!
>
> [1/2] rtc: goldfish: remove dependency to OF
> commit: 3fd00fdc4f11c656a63e6a6280c0bcb63cf109a2
> [2/2] m68k: introduce a virtual m68k machine
> commit: 95631785c64840f3816f7a4cc2ce1a5332f43184
>

Ah, obviously, I'm not applying the m68k patch.

--
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

2021-04-27 17:22:24

by Laurent Vivier

[permalink] [raw]
Subject: Re: [PATCH 2/2] m68k: introduce a virtual m68k machine

Hi,

Le 23/03/2021 à 23:14, Laurent Vivier a écrit :
> This machine allows to have up to 3.2 GiB and 128 Virtio devices.
>
> It is based on android goldfish devices.
>
> Signed-off-by: Laurent Vivier <[email protected]>
> ---
> arch/m68k/Kbuild | 1 +
> arch/m68k/Kconfig.machine | 17 +++
> arch/m68k/configs/virt_defconfig | 93 ++++++++++++++++
> arch/m68k/include/asm/irq.h | 3 +-
> arch/m68k/include/asm/pgtable_mm.h | 7 ++
> arch/m68k/include/asm/setup.h | 44 ++++++--
> arch/m68k/include/asm/virt.h | 26 +++++
> arch/m68k/include/uapi/asm/bootinfo-virt.h | 18 ++++
> arch/m68k/include/uapi/asm/bootinfo.h | 1 +
> arch/m68k/kernel/Makefile | 1 +
> arch/m68k/kernel/head.S | 30 ++++++
> arch/m68k/kernel/setup_mm.c | 9 ++
> arch/m68k/mm/kmap.c | 20 ++--
> arch/m68k/virt/Makefile | 6 ++
> arch/m68k/virt/config.c | 118 +++++++++++++++++++++
> arch/m68k/virt/ints.c | 110 +++++++++++++++++++
> arch/m68k/virt/platform.c | 80 ++++++++++++++
> arch/m68k/virt/timer.c | 91 ++++++++++++++++
> 18 files changed, 658 insertions(+), 17 deletions(-)
> create mode 100644 arch/m68k/configs/virt_defconfig
> create mode 100644 arch/m68k/include/asm/virt.h
> create mode 100644 arch/m68k/include/uapi/asm/bootinfo-virt.h
> create mode 100644 arch/m68k/virt/Makefile
> create mode 100644 arch/m68k/virt/config.c
> create mode 100644 arch/m68k/virt/ints.c
> create mode 100644 arch/m68k/virt/platform.c
> create mode 100644 arch/m68k/virt/timer.c
>

As 5.12 has been released, is this possible to consider having this new machine in the next release?

All changes are contained under arch/m68k and protected by the CONFIG_VIRT flag. This should not
have any impact on the other m68k machines. In any case, I'll be able to maintain the machine and
fix any problem.

Thanks,
Laurent

2021-04-28 13:49:14

by Geert Uytterhoeven

[permalink] [raw]
Subject: Re: [PATCH 2/2] m68k: introduce a virtual m68k machine

Hi Laurent,

On Tue, Apr 27, 2021 at 7:20 PM Laurent Vivier <[email protected]> wrote:
> Le 23/03/2021 à 23:14, Laurent Vivier a écrit :
> > This machine allows to have up to 3.2 GiB and 128 Virtio devices.
> >
> > It is based on android goldfish devices.
> >
> > Signed-off-by: Laurent Vivier <[email protected]>

> As 5.12 has been released, is this possible to consider having this new machine in the next release?
>
> All changes are contained under arch/m68k and protected by the CONFIG_VIRT flag. This should not
> have any impact on the other m68k machines. In any case, I'll be able to maintain the machine and
> fix any problem.

Thanks for the reminder!

Please accept my apologies: I had completely forgotten about your patch.
By the time it reappeared on my radar (due to Alexandre's reply), it was
already too late for v5.13.

I have tested and reviewed your patch, great work!
I'm confident this can make v5.14, with the small nits fixed.

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds

2021-04-28 13:49:49

by Laurent Vivier

[permalink] [raw]
Subject: Re: [PATCH 2/2] m68k: introduce a virtual m68k machine

Le 28/04/2021 à 14:07, Geert Uytterhoeven a écrit :
> Hi Laurent,
>
> On Tue, Apr 27, 2021 at 7:20 PM Laurent Vivier <[email protected]> wrote:
>> Le 23/03/2021 à 23:14, Laurent Vivier a écrit :
>>> This machine allows to have up to 3.2 GiB and 128 Virtio devices.
>>>
>>> It is based on android goldfish devices.
>>>
>>> Signed-off-by: Laurent Vivier <[email protected]>
>
>> As 5.12 has been released, is this possible to consider having this new machine in the next release?
>>
>> All changes are contained under arch/m68k and protected by the CONFIG_VIRT flag. This should not
>> have any impact on the other m68k machines. In any case, I'll be able to maintain the machine and
>> fix any problem.
>
> Thanks for the reminder!
>
> Please accept my apologies: I had completely forgotten about your patch.
> By the time it reappeared on my radar (due to Alexandre's reply), it was
> already too late for v5.13.

No problem.

> I have tested and reviewed your patch, great work!
> I'm confident this can make v5.14, with the small nits fixed.

Thank you for your review.

I will answer to some of your comments and update accordingly my patch.

Thanks,
Laurent

2021-04-28 14:19:17

by Geert Uytterhoeven

[permalink] [raw]
Subject: Re: [PATCH 2/2] m68k: introduce a virtual m68k machine

Hi Laurent,

On Tue, Mar 23, 2021 at 11:14 PM Laurent Vivier <[email protected]> wrote:
> This machine allows to have up to 3.2 GiB and 128 Virtio devices.
>
> It is based on android goldfish devices.
>
> Signed-off-by: Laurent Vivier <[email protected]>

Thanks for your patch!

> --- a/arch/m68k/Kconfig.machine
> +++ b/arch/m68k/Kconfig.machine
> @@ -145,6 +145,23 @@ config SUN3
>
> If you don't want to compile a kernel exclusively for a Sun 3, say N.
>
> +config VIRT
> + bool "Virtual M68k Machine support"
> + depends on MMU
> + select MMU_MOTOROLA if MMU
> + select M68040
> + select LEGACY_TIMER_TICK

Can we avoid selecting this for a new platform?

> + select VIRTIO_MENU

VIRTIO_MENU defaults to y (should it?), so this can be dropped.

> + select VIRTIO_MMIO
> + select GOLDFISH
> + select TTY
> + select GOLDFISH_TTY
> + select RTC_CLASS
> + select RTC_DRV_GOLDFISH

Please sort the selects.

> + help
> + This options enable a pure virtual machine based on m68k,
> + VIRTIO MMIO devices and GOLDFISH interfaces (TTY, RTC, PIC)
> +
> config PILOT
> bool
>
> diff --git a/arch/m68k/configs/virt_defconfig b/arch/m68k/configs/virt_defconfig
> new file mode 100644
> index 000000000000..51842acd5434
> --- /dev/null
> +++ b/arch/m68k/configs/virt_defconfig
> @@ -0,0 +1,93 @@

This is not a minimal config, please run "make savedefconfig"
and replace by the generated defconfig.

Please also add CONFIG_LOCALVERSION="-virt", for consistency with the
other configs.

> --- a/arch/m68k/include/asm/irq.h
> +++ b/arch/m68k/include/asm/irq.h
> @@ -12,7 +12,8 @@
> */
> #if defined(CONFIG_COLDFIRE)
> #define NR_IRQS 256
> -#elif defined(CONFIG_VME) || defined(CONFIG_SUN3) || defined(CONFIG_SUN3X)
> +#elif defined(CONFIG_VME) || defined(CONFIG_SUN3) || \
> + defined(CONFIG_SUN3X) || defined(CONFIG_VIRT)
> #define NR_IRQS 200

Is this related to NUM_VIRT_SOURCES?

Yes it is:

m68k_setup_irq_controller(&virt_irq_chip, handle_simple_irq, IRQ_USER,
NUM_VIRT_SOURCES - IRQ_USER);

> #elif defined(CONFIG_ATARI)
> #define NR_IRQS 141

> --- a/arch/m68k/include/asm/setup.h
> +++ b/arch/m68k/include/asm/setup.h
> @@ -170,6 +180,20 @@ extern unsigned long m68k_machtype;
> # define MACH_TYPE (MACH_SUN3X)
> #endif
>
> +#if !defined(CONFIG_VIRT)
> +# define MACH_IS_VIRT (0)
> +#elif defined(CONFIG_AMIGA) || defined(CONFIG_ATARI) || defined(CONFIG_APOLLO) \
> + || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000) \
> + || defined(CONFIG_HP300) || defined(CONFIG_Q40) \
> + || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147) \
> + || defined(CONFIG_MAC)

Please move the MAC check between the ATARI and APOLLO checks.

> +# define MACH_IS_VIRT (m68k_machtype == MACH_VIRT)
> +#else
> +# define MACH_VIRTONLY

MACH_VIRT_ONLY (albeit unused)

> +# define MACH_IS_VIRT (1)
> +# define MACH_TYPE (MACH_VIRT)
> +#endif
> +
> #ifndef MACH_TYPE
> # define MACH_TYPE (m68k_machtype)
> #endif

> --- /dev/null
> +++ b/arch/m68k/include/asm/virt.h
> @@ -0,0 +1,26 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef __ASM_VIRT_H
> +#define __ASM_VIRT_H
> +
> +#define NUM_VIRT_SOURCES 200
> +
> +struct virt_booter_device_data {
> + unsigned long mmio;
> + unsigned long irq;
> +};
> +
> +struct virt_booter_data {
> + unsigned long qemu_version;
> + struct virt_booter_device_data pic;
> + struct virt_booter_device_data rtc;
> + struct virt_booter_device_data tty;
> + struct virt_booter_device_data ctrl;
> + struct virt_booter_device_data virtio;
> +};
> +
> +extern struct virt_booter_data virt_bi_data;
> +
> +extern void __init virt_init_IRQ(void);
> +extern void __init virt_sched_init(void);
> +
> +#endif
> diff --git a/arch/m68k/include/uapi/asm/bootinfo-virt.h b/arch/m68k/include/uapi/asm/bootinfo-virt.h
> new file mode 100644
> index 000000000000..ab17fd9d200d
> --- /dev/null
> +++ b/arch/m68k/include/uapi/asm/bootinfo-virt.h
> @@ -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 */
> diff --git a/arch/m68k/include/uapi/asm/bootinfo.h b/arch/m68k/include/uapi/asm/bootinfo.h
> index 38d3140381fa..203d9cbf9630 100644
> --- a/arch/m68k/include/uapi/asm/bootinfo.h
> +++ b/arch/m68k/include/uapi/asm/bootinfo.h
> @@ -83,6 +83,7 @@ struct mem_info {
> #define MACH_SUN3X 11
> #define MACH_M54XX 12
> #define MACH_M5441X 13
> +#define MACH_VIRT 14

All of the above are already in use in qemu, so I have to accept them ;-)

(Do I see a missed opportunity for adding DT support?...)

> --- a/arch/m68k/kernel/head.S
> +++ b/arch/m68k/kernel/head.S

> @@ -3186,6 +3203,13 @@ func_start serial_putc,%d0/%d1/%a0/%a1
> 3:
> #endif
>
> +#ifdef CONFIG_VIRT
> + is_not_virt(L(serial_putc_done))

Please jump to a new label before the #endif, to make it easier to add
new platforms.

> +
> + movel L(virt_gf_tty_base),%a1
> + moveb %d0,%a1@(GF_PUT_CHAR)
> +#endif
> +
> L(serial_putc_done):
> func_return serial_putc


> --- a/arch/m68k/mm/kmap.c
> +++ b/arch/m68k/mm/kmap.c

> @@ -293,18 +299,20 @@ EXPORT_SYMBOL(__ioremap);
> */
> void iounmap(void __iomem *addr)
> {
> -#ifdef CONFIG_AMIGA
> - if ((!MACH_IS_AMIGA) ||
> - (((unsigned long)addr < 0x40000000) ||
> - ((unsigned long)addr > 0x60000000)))
> - free_io_area((__force void *)addr);
> +#if defined(CONFIG_AMIGA) || defined(CONFIG_VIRT)

Please split in two separate #ifdefs,...

> + if (MACH_IS_AMIGA &&
> + ((unsigned long)addr >= 0x40000000) &&
> + ((unsigned long)addr < 0x60000000))
> + return;
> + if (MACH_IS_VIRT && (unsigned long)addr >= 0xff000000)
> + return;
> #else

... drop the #else, ...

> #ifdef CONFIG_COLDFIRE
> if (cf_internalio(addr))
> return;
> #endif
> - free_io_area((__force void *)addr);
> #endif

... and drop this #endif

> + free_io_area((__force void *)addr);
> }
> EXPORT_SYMBOL(iounmap);

> --- /dev/null
> +++ b/arch/m68k/virt/config.c
> @@ -0,0 +1,118 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <linux/serial_core.h>
> +
> +#include <asm/bootinfo.h>
> +#include <asm/bootinfo-virt.h>
> +#include <asm/byteorder.h>
> +

Please drop this blank line.

> +#include <asm/machdep.h>
> +#include <asm/virt.h>

> +static void virt_get_model(char *str)
> +{
> + /* str is 80 characters long */
> + sprintf(str, "QEMU Virtual M68K Machine (%d.%d.%d)",

Please use %u for unsigned numbers.

> + (u8)(virt_bi_data.qemu_version >> 24),
> + (u8)(virt_bi_data.qemu_version >> 16),
> + (u8)(virt_bi_data.qemu_version >> 8));
> +}
> +
> +extern void show_registers(struct pt_regs *);

This is unused.

> +void __init config_virt(void)
> +{
> + char earlycon[24];
> +
> + if (!MACH_IS_VIRT)
> + pr_err("ERROR: no Virtual M68k Machine, but %s called!!\n",
> + __func__);

This cannot happen, so please drop.

> diff --git a/arch/m68k/virt/ints.c b/arch/m68k/virt/ints.c
> new file mode 100644
> index 000000000000..aa94cb3b6d96
> --- /dev/null
> +++ b/arch/m68k/virt/ints.c
> @@ -0,0 +1,110 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <linux/types.h>
> +#include <linux/kernel.h>
> +#include <linux/sched.h>
> +#include <linux/sched/debug.h>
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/delay.h>
> +
> +#include <asm/virt.h>
> +#include <asm/irq.h>
> +#include <asm/hwtest.h>
> +#include <asm/irq_regs.h>

Please sort includes.

> +static void virt_irq_enable(struct irq_data *data)
> +{
> + GF_PIC(data->irq).enable = 1 << GF_IRQ(data->irq);
> +}
> +
> +static void virt_irq_disable(struct irq_data *data)
> +{
> + GF_PIC(data->irq).disable = 1 << GF_IRQ(data->irq);
> +}
> +
> +static unsigned int virt_irq_startup(struct irq_data *data)
> +{
> + GF_PIC(data->irq).enable = 1 << GF_IRQ(data->irq);

Just call virt_irq_enable()?

> + return 0;
> +}
> +
> +static void virt_irq_shutdown(struct irq_data *data)
> +{
> + GF_PIC(data->irq).disable = 1 << GF_IRQ(data->irq);
> +}

This is identical to virt_irq_disable(), so you can just use the latter below.

> +
> +static volatile int in_nmi;

This is used inside virt_nmi_handler() only, so please move it there.
> +
> +irqreturn_t virt_nmi_handler(int irq, void *dev_id)
> +{
> + if (in_nmi)
> + return IRQ_HANDLED;
> + in_nmi = 1;
> +
> + pr_info("Non-Maskable Interrupt\n");

pr_warn()? Or another pr_*()?

> + show_registers(get_irq_regs());
> +
> + in_nmi = 0;
> + return IRQ_HANDLED;
> +}
> +
> +static struct irq_chip virt_irq_chip = {
> + .name = "virt",
> + .irq_enable = virt_irq_enable,
> + .irq_disable = virt_irq_disable,
> + .irq_startup = virt_irq_startup,
> + .irq_shutdown = virt_irq_shutdown,

... = virt_irq_disable,

> +};
> +
> +static void goldfish_pic_irq(struct irq_desc *desc)
> +{
> + u32 irq_pending, irq_bit;
> + int irq_num;
> +
> + irq_pending = gf_pic[desc->irq_data.irq - 1].irq_pending;
> + irq_num = IRQ_USER + (desc->irq_data.irq - 1) * 32;
> + irq_bit = 1;
> +
> + do {
> + if (irq_pending & irq_bit) {
> + generic_handle_irq(irq_num);
> + irq_pending &= ~irq_bit;
> + }
> + ++irq_num;
> + irq_bit <<= 1;
> + } while (irq_pending);

This can be simplified by shifting irq_pending instead of irq_bit:

do {
if (irq_pending & 1)
generic_handle_irq(irq_num);

++irq_num;
irq_pending >>= 1;
} while (irq_pending);

Unfortunately m68k doesn't have a single-instruction __ffs().

> +}
> +
> +void __init virt_init_IRQ(void)
> +{
> + int i;
> +
> + m68k_setup_irq_controller(&virt_irq_chip, handle_simple_irq, IRQ_USER,
> + NUM_VIRT_SOURCES - IRQ_USER);
> +
> + for (i = 0; i < 6; i++) {

6 = NUM_VIRT_SOURCES / 32?
If yes, what about the last 8 irqs?

> + irq_set_chained_handler(virt_bi_data.pic.irq + i,
> + goldfish_pic_irq);
> + }

> --- /dev/null
> +++ b/arch/m68k/virt/platform.c
> @@ -0,0 +1,80 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <linux/platform_device.h>
> +#include <linux/interrupt.h>
> +#include <asm/virt.h>
> +#include <asm/irq.h>
> +
> +static struct platform_device virt_m68k_goldfish_tty = {
> + .name = "goldfish_tty",
> + .id = PLATFORM_DEVID_NONE,
> + .num_resources = 2,
> + .resource = (struct resource [2]) { },
> +};
> +static struct platform_device virt_m68k_goldfish_rtc = {
> + .name = "goldfish_rtc",
> + .id = PLATFORM_DEVID_NONE,
> + .num_resources = 2,
> + .resource = (struct resource [2]) { },
> +};
> +
> +#define VIRTIO_BUS_NB 128
> +static struct platform_device virt_m68k_virtio_mmio_device[VIRTIO_BUS_NB];
> +static struct resource virt_m68k_virtio_mmio_resources[VIRTIO_BUS_NB][2];

This consumes more than 40 KiB, even when unused.
While this doesn't matter much for a virtual machine with 3.2 GiB of
RAM, it does matter for running a multi-platform kernel on a real
machine. Hence please allocate dynamically.

> +
> +static int __init virt_platform_init(void)
> +{
> + int err;
> + int i;
> + extern unsigned long min_low_pfn;

Please use reverse Christmas tree declaration order.

> +
> + if (!MACH_IS_VIRT)
> + return -ENODEV;
> +
> + min_low_pfn = 0;

Why is this needed?

> +
> + virt_m68k_goldfish_tty.resource[0].flags = IORESOURCE_MEM;
> + virt_m68k_goldfish_tty.resource[0].start = virt_bi_data.tty.mmio;
> + virt_m68k_goldfish_tty.resource[0].end = virt_bi_data.tty.mmio;
> + virt_m68k_goldfish_tty.resource[1].flags = IORESOURCE_IRQ;
> + virt_m68k_goldfish_tty.resource[1].start = virt_bi_data.tty.irq;
> + virt_m68k_goldfish_tty.resource[1].end = virt_bi_data.tty.irq;
> +
> + err = platform_device_register(&virt_m68k_goldfish_tty);

You could probably save a little bit of memory by calling
platform_device_register_simple() instead.

> + if (err)
> + return err;
> +
> + virt_m68k_goldfish_rtc.resource[0].flags = IORESOURCE_MEM;
> + virt_m68k_goldfish_rtc.resource[0].start = virt_bi_data.rtc.mmio + 0x1000;
> + virt_m68k_goldfish_rtc.resource[0].end = virt_bi_data.rtc.mmio + 0x1fff;
> + virt_m68k_goldfish_rtc.resource[1].flags = IORESOURCE_IRQ;
> + virt_m68k_goldfish_rtc.resource[1].start = virt_bi_data.rtc.irq + 1;
> + virt_m68k_goldfish_rtc.resource[1].end = virt_bi_data.rtc.irq + 1;
> + err = platform_device_register(&virt_m68k_goldfish_rtc);

Likewise.

> --- /dev/null
> +++ b/arch/m68k/virt/timer.c
> @@ -0,0 +1,91 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <linux/interrupt.h>
> +#include <linux/ioport.h>
> +#include <linux/clocksource.h>
> +#include <asm/virt.h>
> +
> +struct goldfish_timer {
> + u32 time_low;
> + u32 time_high;
> + u32 alarm_low;
> + u32 alarm_high;
> + u32 irq_enabled;
> + u32 clear_alarm;
> + u32 alarm_status;
> + u32 clear_interrupt;
> +};
> +
> +#define gf_timer ((volatile struct goldfish_timer *)virt_bi_data.rtc.mmio)
> +
> +static u64 goldfish_timer_read(struct clocksource *cs)
> +{
> + u64 ticks;
> +
> + ticks = gf_timer->time_low;
> + ticks += (u64)gf_timer->time_high << 32;

Can time_low wrap in between the two reads?

> +
> + return ticks;
> +}
> +
> +static struct clocksource goldfish_timer = {
> + .name = "goldfish_timer",
> + .rating = 400,
> + .read = goldfish_timer_read,
> + .mask = CLOCKSOURCE_MASK(64),
> + .flags = 0,
> + .max_idle_ns = LONG_MAX,
> +};
> +
> +static irqreturn_t golfish_timer_handler(int irq, void *dev_id)
> +{
> + unsigned long flags;
> + u64 now;
> +
> + local_irq_save(flags);

Do we need this in an interrupt handler?

> + gf_timer->clear_interrupt = 1;
> +
> + now = gf_timer->time_low;
> + now += (u64)gf_timer->time_high << 32;

now = goldfish_timer_read();

> +
> + legacy_timer_tick(1);
> +
> + now += NSEC_PER_SEC / HZ;
> + gf_timer->alarm_high = now >> 32;

upper_32_bits(now)

> + gf_timer->alarm_low = (u32)now;

lower_32_bits(now)

> + local_irq_restore(flags);
> +
> + return IRQ_HANDLED;
> +}
> +
> +void __init virt_sched_init(void)
> +{
> + u64 now;
> + static struct resource sched_res;

Please use reverse Christmas tree declaration order.

> +
> + sched_res.name = "goldfish_timer";
> + sched_res.start = virt_bi_data.rtc.mmio;
> + sched_res.end = virt_bi_data.rtc.mmio + 0xfff;
> +
> + if (request_resource(&iomem_resource, &sched_res)) {
> + pr_err("Cannot allocate goldfish-timer resource\n");
> + return;
> + }
> +
> + if (request_irq(virt_bi_data.rtc.irq, golfish_timer_handler, IRQF_TIMER,
> + "timer", NULL)) {
> + pr_err("Couldn't register timer interrupt\n");
> + return;
> + }
> +
> + now = gf_timer->time_low;
> + now += (u64)gf_timer->time_high << 32;

now = goldfish_timer_read();

> + now += NSEC_PER_SEC / HZ;
> +
> + gf_timer->clear_interrupt = 1;
> + gf_timer->alarm_high = now >> 32;

upper_32_bits(now)

> + gf_timer->alarm_low = (u32)now;

lower_32_bits(now)

> + gf_timer->irq_enabled = 1;
> +
> + clocksource_register_hz(&goldfish_timer, NSEC_PER_SEC);
> +}

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds

2021-04-28 23:07:59

by Josh Juran

[permalink] [raw]
Subject: Re: [PATCH 2/2] m68k: introduce a virtual m68k machine

On Apr 28, 2021, at 8:04 AM, Geert Uytterhoeven <[email protected]> wrote:

> This can be simplified by shifting irq_pending instead of irq_bit:
>
> do {
> if (irq_pending & 1)
> generic_handle_irq(irq_num);
>
> ++irq_num;
> irq_pending >>= 1;
> } while (irq_pending);
>
> Unfortunately m68k doesn't have a single-instruction __ffs().

The 68000 and 68010 don't, but couldn't the 68020's BFFFO do the job?

Josh

2021-04-29 07:25:58

by Geert Uytterhoeven

[permalink] [raw]
Subject: Re: [PATCH 2/2] m68k: introduce a virtual m68k machine

Hi Josh,

On Thu, Apr 29, 2021 at 1:06 AM Josh Juran <[email protected]> wrote:
> On Apr 28, 2021, at 8:04 AM, Geert Uytterhoeven <[email protected]> wrote:
> > This can be simplified by shifting irq_pending instead of irq_bit:
> >
> > do {
> > if (irq_pending & 1)
> > generic_handle_irq(irq_num);
> >
> > ++irq_num;
> > irq_pending >>= 1;
> > } while (irq_pending);
> >
> > Unfortunately m68k doesn't have a single-instruction __ffs().
>
> The 68000 and 68010 don't, but couldn't the 68020's BFFFO do the job?

I looked at the code generated by gcc for __builtin_ffs(), and while
it did use BFFFO, it needs several other instructions.

The same can be seen in arch/m68k/include/asm/bitops.h:

static inline int ffs(int x)
{
int cnt;

__asm__ ("bfffo %1{#0:#0},%0"
: "=d" (cnt)
: "dm" (x & -x));
return 32 - cnt;
}


Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds

2021-09-30 21:37:19

by Laurent Vivier

[permalink] [raw]
Subject: Re: [PATCH 2/2] m68k: introduce a virtual m68k machine

Le 30/09/2021 à 22:56, John Paul Adrian Glaubitz a écrit :
> Hi Laurent!
>
> On 4/28/21 14:15, Laurent Vivier wrote:
>>> I have tested and reviewed your patch, great work!
>>> I'm confident this can make v5.14, with the small nits fixed.
>>
>> Thank you for your review.
>>
>> I will answer to some of your comments and update accordingly my patch.
>
> It looks like this patch somehow fell off the table, didn't it?
>
> I was hoping to be able to build a virt kernel for Debian/m68k by default
> in the near future.

Yes, I started to update my work according to the comments from Geert but didn't have time to finish.

Especially I tried to remove the LEGACY_TIMER_TICK, but it doesn't work, and as it has been tested
like this by you and most of the other m68k targets uses it I think I will let the patch with it.

I'm going to update my patch to have a v2, at least to have fresh reviews.

Thanks,
Laurent

2021-09-30 21:37:40

by Laurent Vivier

[permalink] [raw]
Subject: Re: [PATCH 2/2] m68k: introduce a virtual m68k machine

Le 28/04/2021 à 14:04, Geert Uytterhoeven a écrit :
> Hi Laurent,
>
> On Tue, Mar 23, 2021 at 11:14 PM Laurent Vivier <[email protected]> wrote:
>> This machine allows to have up to 3.2 GiB and 128 Virtio devices.
>>
>> It is based on android goldfish devices.
>>
>> Signed-off-by: Laurent Vivier <[email protected]>
>
> Thanks for your patch!

Thank you for the review, sorry for the very late answer.

Only two comments before I send a v2.

>> --- a/arch/m68k/Kconfig.machine
>> +++ b/arch/m68k/Kconfig.machine
>> @@ -145,6 +145,23 @@ config SUN3
>>
>> If you don't want to compile a kernel exclusively for a Sun 3, say N.
>>
>> +config VIRT
>> + bool "Virtual M68k Machine support"
>> + depends on MMU
>> + select MMU_MOTOROLA if MMU
>> + select M68040
>> + select LEGACY_TIMER_TICK
>
> Can we avoid selecting this for a new platform?
>

I tried but I was not able to have a working scheduler.

As the machine has been tested with this option and most of the other m68k machines uses it, I will
keep it.

...
>> --- /dev/null
>> +++ b/arch/m68k/virt/platform.c
>> @@ -0,0 +1,80 @@
...
>> +
>> + if (!MACH_IS_VIRT)
>> + return -ENODEV;
>> +
>> + min_low_pfn = 0;
>
> Why is this needed?
>

This is needed to be able to have working DMA in goldfish_tty.

Without this, memory provided for the buffer in goldish_tty_rw() are not usable with DMA and we
cannot transfer the data. If I remember correctly dma_map_single() fails.

I think this is because the memory provided by the kernel is not in the DMA area. But the virt
machine has no DMA...

Perhaps you can propose better solution?

Thanks,
Laurent

Subject: Re: [PATCH 2/2] m68k: introduce a virtual m68k machine

Hi!

On 9/30/21 23:11, Laurent Vivier wrote:
>>> --- a/arch/m68k/Kconfig.machine
>>> +++ b/arch/m68k/Kconfig.machine
>>> @@ -145,6 +145,23 @@ config SUN3
>>>
>>> If you don't want to compile a kernel exclusively for a Sun 3, say N.
>>>
>>> +config VIRT
>>> + bool "Virtual M68k Machine support"
>>> + depends on MMU
>>> + select MMU_MOTOROLA if MMU
>>> + select M68040
>>> + select LEGACY_TIMER_TICK
>>
>> Can we avoid selecting this for a new platform?
>>
>
> I tried but I was not able to have a working scheduler.
>
> As the machine has been tested with this option and most of the other m68k machines uses it, I will
> keep it.

FWIW, the VM in its current form works very well and reliable and has been
in use as a Debian porterbox for almost a year now without any issues.

root@mitchy:~# uname -a
Linux mitchy 5.10.0-rc1-183617-gd7f4e16357f6 #1 Mon Nov 2 12:06:55 CET 2020 m68k GNU/Linux
root@mitchy:~# uptime
23:13:47 up 332 days, 10:04, 1 user, load average: 0.08, 0.05, 0.06
root@mitchy:~#

Would be great if we could get this feature added upstream so I can enable
this kernel configuration in Debian.

Adrian

--
.''`. John Paul Adrian Glaubitz
: :' : Debian Developer - [email protected]
`. `' Freie Universitaet Berlin - [email protected]
`- GPG: 62FF 8A75 84E0 2956 9546 0006 7426 3B37 F5B5 F913

Subject: Re: [PATCH 2/2] m68k: introduce a virtual m68k machine

Hi Laurent!

On 4/28/21 14:15, Laurent Vivier wrote:
>> I have tested and reviewed your patch, great work!
>> I'm confident this can make v5.14, with the small nits fixed.
>
> Thank you for your review.
>
> I will answer to some of your comments and update accordingly my patch.

It looks like this patch somehow fell off the table, didn't it?

I was hoping to be able to build a virt kernel for Debian/m68k by default
in the near future.

Adrian

--
.''`. John Paul Adrian Glaubitz
: :' : Debian Developer - [email protected]
`. `' Freie Universitaet Berlin - [email protected]
`- GPG: 62FF 8A75 84E0 2956 9546 0006 7426 3B37 F5B5 F913

2021-10-01 01:12:14

by Finn Thain

[permalink] [raw]
Subject: Re: [PATCH 2/2] m68k: introduce a virtual m68k machine

On Thu, 30 Sep 2021, Laurent Vivier wrote:

> Le 30/09/2021 à 22:56, John Paul Adrian Glaubitz a écrit :
> >
> > On 4/28/21 14:15, Laurent Vivier wrote:
> >>> I have tested and reviewed your patch, great work!
> >>> I'm confident this can make v5.14, with the small nits fixed.
> >>
> >> Thank you for your review.
> >>
> >> I will answer to some of your comments and update accordingly my patch.
> >
> > It looks like this patch somehow fell off the table, didn't it?
> >
> > I was hoping to be able to build a virt kernel for Debian/m68k by default
> > in the near future.
>
> Yes, I started to update my work according to the comments from Geert but didn't have time to finish.
>
> Especially I tried to remove the LEGACY_TIMER_TICK, but it doesn't work,

There was an RFC patch from Arnd to convert the mac platform from
LEGACY_TIMER_TICK to GENERIC_CLOCKEVENTS:
https://lore.kernel.org/linux-m68k/[email protected]/
Arnd used a periodic clockevent device. I have a developmental branch
based on that patch.

Alternatively, I have a branch that implements a oneshot clockevent
device. This delivers GENERIC_CLOCKEVENTS and NO_HZ. For this I used VIA 1
timer 1 in free-running mode for the clocksource and VIA 1 timer 2 in
one-shot mode for the clockevent device. (But this does require some QEMU
improvements because there's no oneshot-mode in mos6522.c in mainline
QEMU.)

Anyway, it can be done. If you want to pursue it, perhaps we can
collaborate.

> and as it has been tested like this by you and most of the other m68k
> targets uses it I think I will let the patch with it.
>
> I'm going to update my patch to have a v2, at least to have fresh
> reviews.
>
> Thanks,
> Laurent
>