Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <laurent@vivier.eu>
Link: https://lore.kernel.org/r/20220406201523.243733-5-laurent@vivier.eu
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>

authored by

Laurent Vivier and committed by
Geert Uytterhoeven
05d51e42 c92e7ef1

+595 -17
+1
arch/m68k/Kbuild
··· 17 17 obj-$(CONFIG_M68KFPU_EMU) += math-emu/ 18 18 obj-$(CONFIG_M68000) += 68000/ 19 19 obj-$(CONFIG_COLDFIRE) += coldfire/ 20 + obj-$(CONFIG_VIRT) += virt/
+17
arch/m68k/Kconfig.machine
··· 149 149 150 150 If you don't want to compile a kernel exclusively for a Sun 3, say N. 151 151 152 + config VIRT 153 + bool "Virtual M68k Machine support" 154 + depends on MMU 155 + select GENERIC_CLOCKEVENTS 156 + select GOLDFISH 157 + select GOLDFISH_TIMER 158 + select GOLDFISH_TTY 159 + select M68040 160 + select MMU_MOTOROLA if MMU 161 + select RTC_CLASS 162 + select RTC_DRV_GOLDFISH 163 + select TTY 164 + select VIRTIO_MMIO 165 + help 166 + This options enable a pure virtual machine based on m68k, 167 + VIRTIO MMIO devices and GOLDFISH interfaces (TTY, RTC, PIC) 168 + 152 169 config PILOT 153 170 bool 154 171
+68
arch/m68k/configs/virt_defconfig
··· 1 + CONFIG_LOCALVERSION="-virt" 2 + CONFIG_SYSVIPC=y 3 + CONFIG_CGROUPS=y 4 + CONFIG_BLK_CGROUP=y 5 + CONFIG_CGROUP_SCHED=y 6 + CONFIG_CGROUP_PIDS=y 7 + CONFIG_CGROUP_RDMA=y 8 + CONFIG_CGROUP_FREEZER=y 9 + CONFIG_CGROUP_DEVICE=y 10 + CONFIG_CGROUP_CPUACCT=y 11 + CONFIG_VIRT=y 12 + CONFIG_PROC_HARDWARE=y 13 + CONFIG_PARTITION_ADVANCED=y 14 + CONFIG_AMIGA_PARTITION=y 15 + CONFIG_ATARI_PARTITION=y 16 + CONFIG_MAC_PARTITION=y 17 + CONFIG_BSD_DISKLABEL=y 18 + CONFIG_MINIX_SUBPARTITION=y 19 + CONFIG_SOLARIS_X86_PARTITION=y 20 + CONFIG_UNIXWARE_DISKLABEL=y 21 + CONFIG_LDM_PARTITION=y 22 + CONFIG_LDM_DEBUG=y 23 + CONFIG_SUN_PARTITION=y 24 + CONFIG_SYSV68_PARTITION=y 25 + CONFIG_NET=y 26 + CONFIG_PACKET=y 27 + CONFIG_UNIX=y 28 + CONFIG_INET=y 29 + CONFIG_IP_PNP=y 30 + CONFIG_IP_PNP_DHCP=y 31 + CONFIG_IP_PNP_BOOTP=y 32 + CONFIG_CGROUP_NET_PRIO=y 33 + CONFIG_CGROUP_NET_CLASSID=y 34 + CONFIG_NET_9P=y 35 + CONFIG_NET_9P_VIRTIO=y 36 + CONFIG_DEVTMPFS=y 37 + CONFIG_BLK_DEV_LOOP=y 38 + CONFIG_BLK_DEV_RAM=y 39 + CONFIG_VIRTIO_BLK=y 40 + CONFIG_SCSI=y 41 + CONFIG_BLK_DEV_SR=y 42 + CONFIG_SCSI_VIRTIO=y 43 + CONFIG_NETDEVICES=y 44 + CONFIG_VIRTIO_NET=y 45 + CONFIG_INPUT_MOUSEDEV=y 46 + CONFIG_INPUT_EVDEV=y 47 + CONFIG_VIRTIO_CONSOLE=y 48 + CONFIG_HW_RANDOM_VIRTIO=y 49 + CONFIG_DRM=y 50 + CONFIG_DRM_VIRTIO_GPU=y 51 + CONFIG_FB=y 52 + CONFIG_SOUND=y 53 + CONFIG_SND=y 54 + CONFIG_SND_VIRTIO=y 55 + CONFIG_VIRT_DRIVERS=y 56 + CONFIG_VIRTIO_INPUT=y 57 + CONFIG_EXT4_FS=y 58 + CONFIG_AUTOFS_FS=y 59 + CONFIG_ISO9660_FS=y 60 + CONFIG_JOLIET=y 61 + CONFIG_ZISOFS=y 62 + CONFIG_UDF_FS=y 63 + CONFIG_TMPFS=y 64 + CONFIG_TMPFS_POSIX_ACL=y 65 + CONFIG_9P_FS=y 66 + CONFIG_9P_FS_POSIX_ACL=y 67 + CONFIG_9P_FS_SECURITY=y 68 + CONFIG_EARLY_PRINTK=y
+2
arch/m68k/include/asm/config.h
··· 17 17 extern int mvme147_parse_bootinfo(const struct bi_record *record); 18 18 extern int mvme16x_parse_bootinfo(const struct bi_record *record); 19 19 extern int q40_parse_bootinfo(const struct bi_record *record); 20 + extern int virt_parse_bootinfo(const struct bi_record *record); 20 21 21 22 extern void config_amiga(void); 22 23 extern void config_apollo(void); ··· 30 29 extern void config_q40(void); 31 30 extern void config_sun3(void); 32 31 extern void config_sun3x(void); 32 + extern void config_virt(void); 33 33 34 34 #endif /* _M68K_CONFIG_H */
+3
arch/m68k/include/asm/io.h
··· 8 8 #include <asm/io_mm.h> 9 9 #endif 10 10 11 + #define gf_ioread32 ioread32be 12 + #define gf_iowrite32 iowrite32be 13 + 11 14 #include <asm-generic/io.h> 12 15 13 16 #endif /* _M68K_IO_H */
+2 -1
arch/m68k/include/asm/irq.h
··· 12 12 */ 13 13 #if defined(CONFIG_COLDFIRE) 14 14 #define NR_IRQS 256 15 - #elif defined(CONFIG_VME) || defined(CONFIG_SUN3) || defined(CONFIG_SUN3X) 15 + #elif defined(CONFIG_VME) || defined(CONFIG_SUN3) || \ 16 + defined(CONFIG_SUN3X) || defined(CONFIG_VIRT) 16 17 #define NR_IRQS 200 17 18 #elif defined(CONFIG_ATARI) 18 19 #define NR_IRQS 141
+7
arch/m68k/include/asm/pgtable_mm.h
··· 80 80 #elif defined(CONFIG_COLDFIRE) 81 81 #define KMAP_START 0xe0000000 82 82 #define KMAP_END 0xf0000000 83 + #elif defined(CONFIG_VIRT) 84 + #define KMAP_START 0xdf000000 85 + #define KMAP_END 0xff000000 83 86 #else 84 87 #define KMAP_START 0xd0000000 85 88 #define KMAP_END 0xf0000000 ··· 95 92 #elif defined(CONFIG_COLDFIRE) 96 93 #define VMALLOC_START 0xd0000000 97 94 #define VMALLOC_END 0xe0000000 95 + #elif defined(CONFIG_VIRT) 96 + #define VMALLOC_OFFSET PAGE_SIZE 97 + #define VMALLOC_START (((unsigned long) high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) 98 + #define VMALLOC_END KMAP_START 98 99 #else 99 100 /* Just any arbitrary offset to the start of the vmalloc VM area: the 100 101 * current 8MB value just means that there will be a 8MB "hole" after the
+34 -10
arch/m68k/include/asm/setup.h
··· 37 37 #elif defined(CONFIG_ATARI) || defined(CONFIG_MAC) || defined(CONFIG_APOLLO) \ 38 38 || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000) \ 39 39 || defined(CONFIG_HP300) || defined(CONFIG_Q40) \ 40 - || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147) 40 + || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147) \ 41 + || defined(CONFIG_VIRT) 41 42 # define MACH_IS_AMIGA (m68k_machtype == MACH_AMIGA) 42 43 #else 43 44 # define MACH_AMIGA_ONLY ··· 51 50 #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_APOLLO) \ 52 51 || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000) \ 53 52 || defined(CONFIG_HP300) || defined(CONFIG_Q40) \ 54 - || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147) 53 + || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147) \ 54 + || defined(CONFIG_VIRT) 55 55 # define MACH_IS_ATARI (m68k_machtype == MACH_ATARI) 56 56 #else 57 57 # define MACH_ATARI_ONLY ··· 65 63 #elif defined(CONFIG_AMIGA) || defined(CONFIG_ATARI) || defined(CONFIG_APOLLO) \ 66 64 || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000) \ 67 65 || defined(CONFIG_HP300) || defined(CONFIG_Q40) \ 68 - || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147) 66 + || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147) \ 67 + || defined(CONFIG_VIRT) 69 68 # define MACH_IS_MAC (m68k_machtype == MACH_MAC) 70 69 #else 71 70 # define MACH_MAC_ONLY ··· 87 84 #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \ 88 85 || defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000) \ 89 86 || defined(CONFIG_HP300) || defined(CONFIG_Q40) \ 90 - || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147) 87 + || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147) \ 88 + || defined(CONFIG_VIRT) 91 89 # define MACH_IS_APOLLO (m68k_machtype == MACH_APOLLO) 92 90 #else 93 91 # define MACH_APOLLO_ONLY ··· 101 97 #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \ 102 98 || defined(CONFIG_APOLLO) || defined(CONFIG_BVME6000) \ 103 99 || defined(CONFIG_HP300) || defined(CONFIG_Q40) \ 104 - || defined(CONFIG_SUN3X) || defined(CONFIG_MVME16x) 100 + || defined(CONFIG_SUN3X) || defined(CONFIG_MVME16x) \ 101 + || defined(CONFIG_VIRT) 105 102 # define MACH_IS_MVME147 (m68k_machtype == MACH_MVME147) 106 103 #else 107 104 # define MACH_MVME147_ONLY ··· 115 110 #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \ 116 111 || defined(CONFIG_APOLLO) || defined(CONFIG_BVME6000) \ 117 112 || defined(CONFIG_HP300) || defined(CONFIG_Q40) \ 118 - || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147) 113 + || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147) \ 114 + || defined(CONFIG_VIRT) 119 115 # define MACH_IS_MVME16x (m68k_machtype == MACH_MVME16x) 120 116 #else 121 117 # define MACH_MVME16x_ONLY ··· 129 123 #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \ 130 124 || defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x) \ 131 125 || defined(CONFIG_HP300) || defined(CONFIG_Q40) \ 132 - || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147) 126 + || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147) \ 127 + || defined(CONFIG_VIRT) 133 128 # define MACH_IS_BVME6000 (m68k_machtype == MACH_BVME6000) 134 129 #else 135 130 # define MACH_BVME6000_ONLY ··· 143 136 #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \ 144 137 || defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x) \ 145 138 || defined(CONFIG_BVME6000) || defined(CONFIG_Q40) \ 146 - || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147) 139 + || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147) \ 140 + || defined(CONFIG_VIRT) 147 141 # define MACH_IS_HP300 (m68k_machtype == MACH_HP300) 148 142 #else 149 143 # define MACH_HP300_ONLY ··· 157 149 #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \ 158 150 || defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x) \ 159 151 || defined(CONFIG_BVME6000) || defined(CONFIG_HP300) \ 160 - || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147) 152 + || defined(CONFIG_SUN3X) || defined(CONFIG_MVME147) \ 153 + || defined(CONFIG_VIRT) 161 154 # define MACH_IS_Q40 (m68k_machtype == MACH_Q40) 162 155 #else 163 156 # define MACH_Q40_ONLY ··· 171 162 #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \ 172 163 || defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x) \ 173 164 || defined(CONFIG_BVME6000) || defined(CONFIG_HP300) \ 174 - || defined(CONFIG_Q40) || defined(CONFIG_MVME147) 165 + || defined(CONFIG_Q40) || defined(CONFIG_MVME147) \ 166 + || defined(CONFIG_VIRT) 175 167 # define MACH_IS_SUN3X (m68k_machtype == MACH_SUN3X) 176 168 #else 177 169 # define CONFIG_SUN3X_ONLY 178 170 # define MACH_IS_SUN3X (1) 179 171 # define MACH_TYPE (MACH_SUN3X) 172 + #endif 173 + 174 + #if !defined(CONFIG_VIRT) 175 + # define MACH_IS_VIRT (0) 176 + #elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \ 177 + || defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x) \ 178 + || defined(CONFIG_BVME6000) || defined(CONFIG_HP300) \ 179 + || defined(CONFIG_Q40) || defined(CONFIG_SUN3X) \ 180 + || defined(CONFIG_MVME147) 181 + # define MACH_IS_VIRT (m68k_machtype == MACH_VIRT) 182 + #else 183 + # define MACH_VIRT_ONLY 184 + # define MACH_IS_VIRT (1) 185 + # define MACH_TYPE (MACH_VIRT) 180 186 #endif 181 187 182 188 #ifndef MACH_TYPE
+25
arch/m68k/include/asm/virt.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef __ASM_VIRT_H 3 + #define __ASM_VIRT_H 4 + 5 + #define NUM_VIRT_SOURCES 200 6 + 7 + struct virt_booter_device_data { 8 + u32 mmio; 9 + u32 irq; 10 + }; 11 + 12 + struct virt_booter_data { 13 + u32 qemu_version; 14 + struct virt_booter_device_data pic; 15 + struct virt_booter_device_data rtc; 16 + struct virt_booter_device_data tty; 17 + struct virt_booter_device_data ctrl; 18 + struct virt_booter_device_data virtio; 19 + }; 20 + 21 + extern struct virt_booter_data virt_bi_data; 22 + 23 + extern void __init virt_init_IRQ(void); 24 + 25 + #endif
+18
arch/m68k/include/uapi/asm/bootinfo-virt.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 + /* 3 + * asm/bootinfo-virt.h -- Virtual-m68k-specific boot information definitions 4 + */ 5 + 6 + #ifndef _UAPI_ASM_M68K_BOOTINFO_VIRT_H 7 + #define _UAPI_ASM_M68K_BOOTINFO_VIRT_H 8 + 9 + #define BI_VIRT_QEMU_VERSION 0x8000 10 + #define BI_VIRT_GF_PIC_BASE 0x8001 11 + #define BI_VIRT_GF_RTC_BASE 0x8002 12 + #define BI_VIRT_GF_TTY_BASE 0x8003 13 + #define BI_VIRT_VIRTIO_BASE 0x8004 14 + #define BI_VIRT_CTRL_BASE 0x8005 15 + 16 + #define VIRT_BOOTI_VERSION MK_BI_VERSION(2, 0) 17 + 18 + #endif /* _UAPI_ASM_M68K_BOOTINFO_MAC_H */
+1
arch/m68k/include/uapi/asm/bootinfo.h
··· 83 83 #define MACH_SUN3X 11 84 84 #define MACH_M54XX 12 85 85 #define MACH_M5441X 13 86 + #define MACH_VIRT 14 86 87 87 88 88 89 /*
+1
arch/m68k/kernel/Makefile
··· 11 11 extra-$(CONFIG_HP300) := head.o 12 12 extra-$(CONFIG_Q40) := head.o 13 13 extra-$(CONFIG_SUN3X) := head.o 14 + extra-$(CONFIG_VIRT) := head.o 14 15 extra-$(CONFIG_SUN3) := sun3-head.o 15 16 extra-y += vmlinux.lds 16 17
+31
arch/m68k/kernel/head.S
··· 262 262 #include <asm/bootinfo-hp300.h> 263 263 #include <asm/bootinfo-mac.h> 264 264 #include <asm/bootinfo-q40.h> 265 + #include <asm/bootinfo-virt.h> 265 266 #include <asm/bootinfo-vme.h> 266 267 #include <asm/setup.h> 267 268 #include <asm/entry.h> ··· 535 534 #define is_not_apollo(lab) cmpl &MACH_APOLLO,%pc@(m68k_machtype); jne lab 536 535 #define is_not_q40(lab) cmpl &MACH_Q40,%pc@(m68k_machtype); jne lab 537 536 #define is_not_sun3x(lab) cmpl &MACH_SUN3X,%pc@(m68k_machtype); jne lab 537 + #define is_not_virt(lab) cmpl &MACH_VIRT,%pc@(m68k_machtype); jne lab 538 538 539 539 #define hasnt_leds(lab) cmpl &MACH_HP300,%pc@(m68k_machtype); \ 540 540 jeq 42f; \ ··· 649 647 L(test_notmac): 650 648 #endif /* CONFIG_MAC */ 651 649 650 + #ifdef CONFIG_VIRT 651 + is_not_virt(L(test_notvirt)) 652 + 653 + get_bi_record BI_VIRT_GF_TTY_BASE 654 + lea %pc@(L(virt_gf_tty_base)),%a1 655 + movel %a0@,%a1@ 656 + L(test_notvirt): 657 + #endif /* CONFIG_VIRT */ 652 658 653 659 /* 654 660 * There are ultimately two pieces of information we want for all kinds of ··· 1245 1235 jbra L(mmu_init_done) 1246 1236 1247 1237 L(notsun3x): 1238 + #endif 1239 + 1240 + #ifdef CONFIG_VIRT 1241 + is_not_virt(L(novirt)) 1242 + mmu_map_tt #1,#0xFF000000,#0x01000000,#_PAGE_NOCACHE_S 1243 + jbra L(mmu_init_done) 1244 + L(novirt): 1248 1245 #endif 1249 1246 1250 1247 #ifdef CONFIG_APOLLO ··· 3203 3186 3: 3204 3187 #endif 3205 3188 3189 + #ifdef CONFIG_VIRT 3190 + is_not_virt(1f) 3191 + 3192 + movel L(virt_gf_tty_base),%a1 3193 + movel %d0,%a1@(GF_PUT_CHAR) 3194 + 1: 3195 + #endif 3196 + 3206 3197 L(serial_putc_done): 3207 3198 func_return serial_putc 3208 3199 ··· 3890 3865 L(q40_do_debug): 3891 3866 .long 0 3892 3867 #endif 3868 + 3869 + #if defined(CONFIG_VIRT) 3870 + GF_PUT_CHAR = 0x00 3871 + L(virt_gf_tty_base): 3872 + .long 0 3873 + #endif /* CONFIG_VIRT */
+7
arch/m68k/kernel/setup_mm.c
··· 181 181 unknown = hp300_parse_bootinfo(record); 182 182 else if (MACH_IS_APOLLO) 183 183 unknown = apollo_parse_bootinfo(record); 184 + else if (MACH_IS_VIRT) 185 + unknown = virt_parse_bootinfo(record); 184 186 else 185 187 unknown = 1; 186 188 } ··· 312 310 cf_bootmem_alloc(); 313 311 cf_mmu_context_init(); 314 312 config_BSP(NULL, 0); 313 + break; 314 + #endif 315 + #ifdef CONFIG_VIRT 316 + case MACH_VIRT: 317 + config_virt(); 315 318 break; 316 319 #endif 317 320 default:
+15 -6
arch/m68k/mm/kmap.c
··· 179 179 return (void __iomem *)physaddr; 180 180 } 181 181 #endif 182 + #ifdef CONFIG_VIRT 183 + if (MACH_IS_VIRT) { 184 + if (physaddr >= 0xff000000 && cacheflag == IOMAP_NOCACHE_SER) 185 + return (void __iomem *)physaddr; 186 + } 187 + #endif 182 188 #ifdef CONFIG_COLDFIRE 183 189 if (__cf_internalio(physaddr)) 184 190 return (void __iomem *) physaddr; ··· 299 293 void iounmap(void __iomem *addr) 300 294 { 301 295 #ifdef CONFIG_AMIGA 302 - if ((!MACH_IS_AMIGA) || 303 - (((unsigned long)addr < 0x40000000) || 304 - ((unsigned long)addr > 0x60000000))) 305 - free_io_area((__force void *)addr); 306 - #else 296 + if (MACH_IS_AMIGA && 297 + ((unsigned long)addr >= 0x40000000) && 298 + ((unsigned long)addr < 0x60000000)) 299 + return; 300 + #endif 301 + #ifdef CONFIG_VIRT 302 + if (MACH_IS_VIRT && (unsigned long)addr >= 0xff000000) 303 + return; 304 + #endif 307 305 #ifdef CONFIG_COLDFIRE 308 306 if (cf_internalio(addr)) 309 307 return; 310 308 #endif 311 309 free_io_area((__force void *)addr); 312 - #endif 313 310 } 314 311 EXPORT_SYMBOL(iounmap); 315 312
+6
arch/m68k/virt/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + # 3 + # Makefile for Linux arch/m68k/virt source directory 4 + # 5 + 6 + obj-y := config.o ints.o platform.o
+130
arch/m68k/virt/config.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <linux/serial_core.h> 4 + #include <clocksource/timer-goldfish.h> 5 + 6 + #include <asm/bootinfo.h> 7 + #include <asm/bootinfo-virt.h> 8 + #include <asm/byteorder.h> 9 + #include <asm/machdep.h> 10 + #include <asm/virt.h> 11 + #include <asm/config.h> 12 + 13 + struct virt_booter_data virt_bi_data; 14 + 15 + #define VIRT_CTRL_REG_FEATURES 0x00 16 + #define VIRT_CTRL_REG_CMD 0x04 17 + 18 + static struct resource ctrlres; 19 + 20 + enum { 21 + CMD_NOOP, 22 + CMD_RESET, 23 + CMD_HALT, 24 + CMD_PANIC, 25 + }; 26 + 27 + static void virt_get_model(char *str) 28 + { 29 + /* str is 80 characters long */ 30 + sprintf(str, "QEMU Virtual M68K Machine (%u.%u.%u)", 31 + (u8)(virt_bi_data.qemu_version >> 24), 32 + (u8)(virt_bi_data.qemu_version >> 16), 33 + (u8)(virt_bi_data.qemu_version >> 8)); 34 + } 35 + 36 + static void virt_halt(void) 37 + { 38 + void __iomem *base = (void __iomem *)virt_bi_data.ctrl.mmio; 39 + 40 + iowrite32be(CMD_HALT, base + VIRT_CTRL_REG_CMD); 41 + local_irq_disable(); 42 + while (1) 43 + ; 44 + } 45 + 46 + static void virt_reset(void) 47 + { 48 + void __iomem *base = (void __iomem *)virt_bi_data.ctrl.mmio; 49 + 50 + iowrite32be(CMD_RESET, base + VIRT_CTRL_REG_CMD); 51 + local_irq_disable(); 52 + while (1) 53 + ; 54 + } 55 + 56 + /* 57 + * Parse a virtual-m68k-specific record in the bootinfo 58 + */ 59 + 60 + int __init virt_parse_bootinfo(const struct bi_record *record) 61 + { 62 + int unknown = 0; 63 + const void *data = record->data; 64 + 65 + switch (be16_to_cpu(record->tag)) { 66 + case BI_VIRT_QEMU_VERSION: 67 + virt_bi_data.qemu_version = be32_to_cpup(data); 68 + break; 69 + case BI_VIRT_GF_PIC_BASE: 70 + virt_bi_data.pic.mmio = be32_to_cpup(data); 71 + data += 4; 72 + virt_bi_data.pic.irq = be32_to_cpup(data); 73 + break; 74 + case BI_VIRT_GF_RTC_BASE: 75 + virt_bi_data.rtc.mmio = be32_to_cpup(data); 76 + data += 4; 77 + virt_bi_data.rtc.irq = be32_to_cpup(data); 78 + break; 79 + case BI_VIRT_GF_TTY_BASE: 80 + virt_bi_data.tty.mmio = be32_to_cpup(data); 81 + data += 4; 82 + virt_bi_data.tty.irq = be32_to_cpup(data); 83 + break; 84 + case BI_VIRT_CTRL_BASE: 85 + virt_bi_data.ctrl.mmio = be32_to_cpup(data); 86 + data += 4; 87 + virt_bi_data.ctrl.irq = be32_to_cpup(data); 88 + break; 89 + case BI_VIRT_VIRTIO_BASE: 90 + virt_bi_data.virtio.mmio = be32_to_cpup(data); 91 + data += 4; 92 + virt_bi_data.virtio.irq = be32_to_cpup(data); 93 + break; 94 + default: 95 + unknown = 1; 96 + break; 97 + } 98 + return unknown; 99 + } 100 + 101 + static void __init virt_sched_init(void) 102 + { 103 + goldfish_timer_init(virt_bi_data.rtc.irq, 104 + (void __iomem *)virt_bi_data.rtc.mmio); 105 + } 106 + 107 + void __init config_virt(void) 108 + { 109 + char earlycon[24]; 110 + 111 + snprintf(earlycon, sizeof(earlycon), "early_gf_tty,0x%08x", 112 + virt_bi_data.tty.mmio); 113 + setup_earlycon(earlycon); 114 + 115 + ctrlres = (struct resource) 116 + DEFINE_RES_MEM_NAMED(virt_bi_data.ctrl.mmio, 0x100, 117 + "virtctrl"); 118 + 119 + if (request_resource(&iomem_resource, &ctrlres)) { 120 + pr_err("Cannot allocate virt controller resource\n"); 121 + return; 122 + } 123 + 124 + mach_init_IRQ = virt_init_IRQ; 125 + mach_sched_init = virt_sched_init; 126 + mach_get_model = virt_get_model; 127 + mach_reset = virt_reset; 128 + mach_halt = virt_halt; 129 + mach_power_off = virt_halt; 130 + }
+155
arch/m68k/virt/ints.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <linux/delay.h> 4 + #include <linux/interrupt.h> 5 + #include <linux/irq.h> 6 + #include <linux/kernel.h> 7 + #include <linux/sched.h> 8 + #include <linux/sched/debug.h> 9 + #include <linux/types.h> 10 + #include <linux/ioport.h> 11 + 12 + #include <asm/hwtest.h> 13 + #include <asm/irq.h> 14 + #include <asm/irq_regs.h> 15 + #include <asm/virt.h> 16 + 17 + #define GFPIC_REG_IRQ_PENDING 0x04 18 + #define GFPIC_REG_IRQ_DISABLE_ALL 0x08 19 + #define GFPIC_REG_IRQ_DISABLE 0x0c 20 + #define GFPIC_REG_IRQ_ENABLE 0x10 21 + 22 + extern void show_registers(struct pt_regs *regs); 23 + 24 + static struct resource picres[6]; 25 + static const char *picname[6] = { 26 + "goldfish_pic.0", 27 + "goldfish_pic.1", 28 + "goldfish_pic.2", 29 + "goldfish_pic.3", 30 + "goldfish_pic.4", 31 + "goldfish_pic.5" 32 + }; 33 + 34 + /* 35 + * 6 goldfish-pic for CPU IRQ #1 to IRQ #6 36 + * CPU IRQ #1 -> PIC #1 37 + * IRQ #1 to IRQ #31 -> unused 38 + * IRQ #32 -> goldfish-tty 39 + * CPU IRQ #2 -> PIC #2 40 + * IRQ #1 to IRQ #32 -> virtio-mmio from 1 to 32 41 + * CPU IRQ #3 -> PIC #3 42 + * IRQ #1 to IRQ #32 -> virtio-mmio from 33 to 64 43 + * CPU IRQ #4 -> PIC #4 44 + * IRQ #1 to IRQ #32 -> virtio-mmio from 65 to 96 45 + * CPU IRQ #5 -> PIC #5 46 + * IRQ #1 to IRQ #32 -> virtio-mmio from 97 to 128 47 + * CPU IRQ #6 -> PIC #6 48 + * IRQ #1 -> goldfish-timer 49 + * IRQ #2 -> goldfish-rtc 50 + * IRQ #3 to IRQ #32 -> unused 51 + * CPU IRQ #7 -> NMI 52 + */ 53 + 54 + static u32 gfpic_read(int pic, int reg) 55 + { 56 + void __iomem *base = (void __iomem *)(virt_bi_data.pic.mmio + 57 + pic * 0x1000); 58 + 59 + return ioread32be(base + reg); 60 + } 61 + 62 + static void gfpic_write(u32 value, int pic, int reg) 63 + { 64 + void __iomem *base = (void __iomem *)(virt_bi_data.pic.mmio + 65 + pic * 0x1000); 66 + 67 + iowrite32be(value, base + reg); 68 + } 69 + 70 + #define GF_PIC(irq) ((irq - IRQ_USER) / 32) 71 + #define GF_IRQ(irq) ((irq - IRQ_USER) % 32) 72 + 73 + static void virt_irq_enable(struct irq_data *data) 74 + { 75 + gfpic_write(BIT(GF_IRQ(data->irq)), GF_PIC(data->irq), 76 + GFPIC_REG_IRQ_ENABLE); 77 + } 78 + 79 + static void virt_irq_disable(struct irq_data *data) 80 + { 81 + gfpic_write(BIT(GF_IRQ(data->irq)), GF_PIC(data->irq), 82 + GFPIC_REG_IRQ_DISABLE); 83 + } 84 + 85 + static unsigned int virt_irq_startup(struct irq_data *data) 86 + { 87 + virt_irq_enable(data); 88 + return 0; 89 + } 90 + 91 + static irqreturn_t virt_nmi_handler(int irq, void *dev_id) 92 + { 93 + static int in_nmi; 94 + 95 + if (READ_ONCE(in_nmi)) 96 + return IRQ_HANDLED; 97 + WRITE_ONCE(in_nmi, 1); 98 + 99 + pr_warn("Non-Maskable Interrupt\n"); 100 + show_registers(get_irq_regs()); 101 + 102 + WRITE_ONCE(in_nmi, 0); 103 + return IRQ_HANDLED; 104 + } 105 + 106 + static struct irq_chip virt_irq_chip = { 107 + .name = "virt", 108 + .irq_enable = virt_irq_enable, 109 + .irq_disable = virt_irq_disable, 110 + .irq_startup = virt_irq_startup, 111 + .irq_shutdown = virt_irq_disable, 112 + }; 113 + 114 + static void goldfish_pic_irq(struct irq_desc *desc) 115 + { 116 + u32 irq_pending; 117 + unsigned int irq_num; 118 + unsigned int pic = desc->irq_data.irq - 1; 119 + 120 + irq_pending = gfpic_read(pic, GFPIC_REG_IRQ_PENDING); 121 + irq_num = IRQ_USER + pic * 32; 122 + 123 + do { 124 + if (irq_pending & 1) 125 + generic_handle_irq(irq_num); 126 + ++irq_num; 127 + irq_pending >>= 1; 128 + } while (irq_pending); 129 + } 130 + 131 + void __init virt_init_IRQ(void) 132 + { 133 + unsigned int i; 134 + 135 + m68k_setup_irq_controller(&virt_irq_chip, handle_simple_irq, IRQ_USER, 136 + NUM_VIRT_SOURCES - IRQ_USER); 137 + 138 + for (i = 0; i < 6; i++) { 139 + 140 + picres[i] = (struct resource) 141 + DEFINE_RES_MEM_NAMED(virt_bi_data.pic.mmio + i * 0x1000, 142 + 0x1000, picname[i]); 143 + if (request_resource(&iomem_resource, &picres[i])) { 144 + pr_err("Cannot allocate %s resource\n", picname[i]); 145 + return; 146 + } 147 + 148 + irq_set_chained_handler(virt_bi_data.pic.irq + i, 149 + goldfish_pic_irq); 150 + } 151 + 152 + if (request_irq(IRQ_AUTO_7, virt_nmi_handler, 0, "NMI", 153 + virt_nmi_handler)) 154 + pr_err("Couldn't register NMI\n"); 155 + }
+72
arch/m68k/virt/platform.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <linux/platform_device.h> 4 + #include <linux/interrupt.h> 5 + #include <linux/memblock.h> 6 + #include <asm/virt.h> 7 + #include <asm/irq.h> 8 + 9 + #define VIRTIO_BUS_NB 128 10 + 11 + static int __init virt_virtio_init(unsigned int id) 12 + { 13 + const struct resource res[] = { 14 + DEFINE_RES_MEM(virt_bi_data.virtio.mmio + id * 0x200, 0x200), 15 + DEFINE_RES_IRQ(virt_bi_data.virtio.irq + id), 16 + }; 17 + struct platform_device *pdev; 18 + 19 + pdev = platform_device_register_simple("virtio-mmio", id, 20 + res, ARRAY_SIZE(res)); 21 + if (IS_ERR(pdev)) 22 + return PTR_ERR(pdev); 23 + 24 + return 0; 25 + } 26 + 27 + static int __init virt_platform_init(void) 28 + { 29 + const struct resource goldfish_tty_res[] = { 30 + DEFINE_RES_MEM(virt_bi_data.tty.mmio, 1), 31 + DEFINE_RES_IRQ(virt_bi_data.tty.irq), 32 + }; 33 + /* this is the second gf-rtc, the first one is used by the scheduler */ 34 + const struct resource goldfish_rtc_res[] = { 35 + DEFINE_RES_MEM(virt_bi_data.rtc.mmio + 0x1000, 0x1000), 36 + DEFINE_RES_IRQ(virt_bi_data.rtc.irq + 1), 37 + }; 38 + struct platform_device *pdev; 39 + unsigned int i; 40 + 41 + if (!MACH_IS_VIRT) 42 + return -ENODEV; 43 + 44 + /* We need this to have DMA'able memory provided to goldfish-tty */ 45 + min_low_pfn = 0; 46 + 47 + pdev = platform_device_register_simple("goldfish_tty", 48 + PLATFORM_DEVID_NONE, 49 + goldfish_tty_res, 50 + ARRAY_SIZE(goldfish_tty_res)); 51 + if (IS_ERR(pdev)) 52 + return PTR_ERR(pdev); 53 + 54 + pdev = platform_device_register_simple("goldfish_rtc", 55 + PLATFORM_DEVID_NONE, 56 + goldfish_rtc_res, 57 + ARRAY_SIZE(goldfish_rtc_res)); 58 + if (IS_ERR(pdev)) 59 + return PTR_ERR(pdev); 60 + 61 + for (i = 0; i < VIRTIO_BUS_NB; i++) { 62 + int err; 63 + 64 + err = virt_virtio_init(i); 65 + if (err) 66 + return err; 67 + } 68 + 69 + return 0; 70 + } 71 + 72 + arch_initcall(virt_platform_init);