github.com/kata-containers/runtime@v0.0.0-20210505125100-04f29832a923/virtcontainers/qemu_s390x.go (about) 1 // Copyright (c) 2018 IBM 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 // 5 6 package virtcontainers 7 8 import ( 9 "fmt" 10 "time" 11 12 govmmQemu "github.com/kata-containers/govmm/qemu" 13 "github.com/kata-containers/runtime/virtcontainers/device/config" 14 "github.com/kata-containers/runtime/virtcontainers/types" 15 ) 16 17 type qemuS390x struct { 18 // inherit from qemuArchBase, overwrite methods if needed 19 qemuArchBase 20 } 21 22 const defaultQemuPath = "/usr/bin/qemu-system-s390x" 23 24 const defaultQemuMachineType = QemuCCWVirtio 25 26 const defaultQemuMachineOptions = "accel=kvm" 27 28 const virtioSerialCCW = "virtio-serial-ccw" 29 30 const qmpMigrationWaitTimeout = 5 * time.Second 31 32 var qemuPaths = map[string]string{ 33 QemuCCWVirtio: defaultQemuPath, 34 } 35 36 // Verify needed parameters 37 var kernelParams = []Param{ 38 {"console", "ttysclp0"}, 39 } 40 41 var ccwbridge = types.NewBridge(types.CCW, "", make(map[uint32]string, types.CCWBridgeMaxCapacity), 0) 42 43 var supportedQemuMachines = []govmmQemu.Machine{ 44 { 45 Type: QemuCCWVirtio, 46 Options: defaultQemuMachineOptions, 47 }, 48 } 49 50 // MaxQemuVCPUs returns the maximum number of vCPUs supported 51 func MaxQemuVCPUs() uint32 { 52 // Max number of virtual Cpu defined in qemu. See 53 // https://github.com/qemu/qemu/blob/80422b00196a7af4c6efb628fae0ad8b644e98af/target/s390x/cpu.h#L55 54 // #define S390_MAX_CPUS 248 55 return uint32(248) 56 } 57 58 func newQemuArch(config HypervisorConfig) qemuArch { 59 machineType := config.HypervisorMachineType 60 if machineType == "" { 61 machineType = defaultQemuMachineType 62 } 63 64 qemuMachines := make([]govmmQemu.Machine, len(supportedQemuMachines)) 65 copy(qemuMachines, supportedQemuMachines) 66 67 q := &qemuS390x{ 68 qemuArchBase{ 69 machineType: machineType, 70 memoryOffset: config.MemOffset, 71 qemuPaths: qemuPaths, 72 supportedQemuMachines: qemuMachines, 73 kernelParamsNonDebug: kernelParamsNonDebug, 74 kernelParamsDebug: kernelParamsDebug, 75 kernelParams: kernelParams, 76 }, 77 } 78 // Set first bridge type to CCW 79 q.Bridges = append(q.Bridges, ccwbridge) 80 81 if config.ImagePath != "" { 82 q.kernelParams = append(q.kernelParams, commonVirtioblkKernelRootParams...) 83 q.kernelParamsNonDebug = append(q.kernelParamsNonDebug, kernelParamsSystemdNonDebug...) 84 q.kernelParamsDebug = append(q.kernelParamsDebug, kernelParamsSystemdDebug...) 85 } 86 87 return q 88 } 89 90 func (q *qemuS390x) bridges(number uint32) { 91 q.Bridges = genericBridges(number, q.machineType) 92 } 93 94 // appendConsole appends a console to devices. 95 // The function has been overwriten to correctly set the driver to the CCW device 96 func (q *qemuS390x) appendConsole(devices []govmmQemu.Device, path string) ([]govmmQemu.Device, error) { 97 id := "serial0" 98 addr, b, err := q.addDeviceToBridge(id, types.CCW) 99 if err != nil { 100 return devices, fmt.Errorf("Failed to append console %v", err) 101 } 102 103 var devno string 104 devno, err = b.AddressFormatCCW(addr) 105 if err != nil { 106 return devices, fmt.Errorf("Failed to append console %v", err) 107 } 108 109 serial := govmmQemu.SerialDevice{ 110 Driver: virtioSerialCCW, 111 ID: id, 112 DisableModern: q.nestedRun, 113 DevNo: devno, 114 } 115 116 devices = append(devices, serial) 117 118 console := govmmQemu.CharDevice{ 119 Driver: govmmQemu.Console, 120 Backend: govmmQemu.Socket, 121 DeviceID: "console0", 122 ID: "charconsole0", 123 Path: path, 124 } 125 126 devices = append(devices, console) 127 128 return devices, nil 129 } 130 131 func (q *qemuS390x) appendImage(devices []govmmQemu.Device, path string) ([]govmmQemu.Device, error) { 132 drive, err := genericImage(path) 133 if err != nil { 134 return nil, err 135 } 136 return q.appendCCWBlockDevice(devices, drive) 137 } 138 139 func (q *qemuS390x) appendBlockDevice(devices []govmmQemu.Device, drive config.BlockDrive) ([]govmmQemu.Device, error) { 140 return q.appendCCWBlockDevice(devices, drive) 141 } 142 143 func (q *qemuS390x) appendCCWBlockDevice(devices []govmmQemu.Device, drive config.BlockDrive) ([]govmmQemu.Device, error) { 144 d, err := genericBlockDevice(drive, false) 145 if err != nil { 146 return devices, fmt.Errorf("Failed to append blk-dev %v", err) 147 } 148 addr, b, err := q.addDeviceToBridge(drive.ID, types.CCW) 149 if err != nil { 150 return devices, fmt.Errorf("Failed to append blk-dev %v", err) 151 } 152 d.DevNo, err = b.AddressFormatCCW(addr) 153 if err != nil { 154 return devices, fmt.Errorf("Failed to append blk-dev %v", err) 155 } 156 devices = append(devices, d) 157 return devices, nil 158 } 159 160 // appendVhostUserDevice throws an error if vhost devices are tried to be used. 161 // See issue https://github.com/kata-containers/runtime/issues/659 162 func (q *qemuS390x) appendVhostUserDevice(devices []govmmQemu.Device, attr config.VhostUserDeviceAttrs) ([]govmmQemu.Device, error) { 163 return nil, fmt.Errorf("No vhost-user devices supported on s390x") 164 } 165 166 // supportGuestMemoryHotplug return false for s390x architecture. The pc-dimm backend device for s390x 167 // is not support. PC-DIMM is not listed in the devices supported by qemu-system-s390x -device help 168 func (q *qemuS390x) supportGuestMemoryHotplug() bool { 169 return false 170 } 171 172 func (q *qemuS390x) appendNetwork(devices []govmmQemu.Device, endpoint Endpoint) ([]govmmQemu.Device, error) { 173 d, err := genericNetwork(endpoint, false, false, q.networkIndex) 174 if err != nil { 175 return devices, fmt.Errorf("Failed to append network %v", err) 176 } 177 q.networkIndex++ 178 addr, b, err := q.addDeviceToBridge(d.ID, types.CCW) 179 if err != nil { 180 return devices, fmt.Errorf("Failed to append network %v", err) 181 } 182 d.DevNo, err = b.AddressFormatCCW(addr) 183 if err != nil { 184 return devices, fmt.Errorf("Failed to append network %v", err) 185 } 186 187 devices = append(devices, d) 188 return devices, nil 189 } 190 191 func (q *qemuS390x) appendRNGDevice(devices []govmmQemu.Device, rngDev config.RNGDev) ([]govmmQemu.Device, error) { 192 addr, b, err := q.addDeviceToBridge(rngDev.ID, types.CCW) 193 if err != nil { 194 return devices, fmt.Errorf("Failed to append RNG-Device %v", err) 195 } 196 var devno string 197 devno, err = b.AddressFormatCCW(addr) 198 if err != nil { 199 return devices, fmt.Errorf("Failed to append RNG-Device %v", err) 200 } 201 202 devices = append(devices, 203 govmmQemu.RngDevice{ 204 ID: rngDev.ID, 205 Filename: rngDev.Filename, 206 DevNo: devno, 207 }, 208 ) 209 210 return devices, nil 211 } 212 213 func (q *qemuS390x) append9PVolume(devices []govmmQemu.Device, volume types.Volume) ([]govmmQemu.Device, error) { 214 if volume.MountTag == "" || volume.HostPath == "" { 215 return devices, nil 216 } 217 d := generic9PVolume(volume, false) 218 addr, b, err := q.addDeviceToBridge(d.ID, types.CCW) 219 if err != nil { 220 return devices, fmt.Errorf("Failed to append 9p-Volume %v", err) 221 } 222 d.DevNo, err = b.AddressFormatCCW(addr) 223 if err != nil { 224 return devices, fmt.Errorf("Failed to append 9p-Volume %v", err) 225 } 226 devices = append(devices, d) 227 return devices, nil 228 } 229 230 // appendBridges appends to devices the given bridges 231 func (q *qemuS390x) appendBridges(devices []govmmQemu.Device) []govmmQemu.Device { 232 return genericAppendBridges(devices, q.Bridges, q.machineType) 233 } 234 235 func (q *qemuS390x) appendSCSIController(devices []govmmQemu.Device, enableIOThreads bool) ([]govmmQemu.Device, *govmmQemu.IOThread, error) { 236 d, t := genericSCSIController(enableIOThreads, q.nestedRun) 237 addr, b, err := q.addDeviceToBridge(d.ID, types.CCW) 238 if err != nil { 239 return devices, nil, fmt.Errorf("Failed to append scsi-controller %v", err) 240 } 241 d.DevNo, err = b.AddressFormatCCW(addr) 242 if err != nil { 243 return devices, nil, fmt.Errorf("Failed to append scsi-controller %v", err) 244 } 245 246 devices = append(devices, d) 247 return devices, t, nil 248 } 249 250 func (q *qemuS390x) appendVSock(devices []govmmQemu.Device, vsock types.VSock) ([]govmmQemu.Device, error) { 251 var devno string 252 id := fmt.Sprintf("vsock-%d", vsock.ContextID) 253 addr, b, err := q.addDeviceToBridge(id, types.CCW) 254 if err != nil { 255 return devices, fmt.Errorf("Failed to append VSock: %v", err) 256 } 257 devno, err = b.AddressFormatCCW(addr) 258 if err != nil { 259 return devices, fmt.Errorf("Failed to append VSock: %v", err) 260 } 261 devices = append(devices, 262 govmmQemu.VSOCKDevice{ 263 ID: id, 264 ContextID: vsock.ContextID, 265 VHostFD: vsock.VhostFd, 266 DisableModern: false, 267 DevNo: devno, 268 }, 269 ) 270 271 return devices, nil 272 273 } 274 275 func (q *qemuS390x) appendIOMMU(devices []govmmQemu.Device) ([]govmmQemu.Device, error) { 276 return devices, fmt.Errorf("S390x does not support appending a vIOMMU") 277 }