feat(region,host): riscv64 cpu arch support (#24126)

* feat(region,host): riscv64 cpu arch support

* fix(region,host): compatible riscv64

* fix(host): add qemu v10.0.7 support
This commit is contained in:
wanyaoqi
2026-02-01 20:28:45 +08:00
committed by GitHub
parent a92d59e4df
commit 3d5bff680d
35 changed files with 459 additions and 66 deletions

View File

@@ -1,4 +1,4 @@
FROM registry.cn-beijing.aliyuncs.com/yunionio/host-deployer-base:1.5.3
FROM registry.cn-beijing.aliyuncs.com/yunionio/host-deployer-base:1.5.5
LABEL maintainer="Yaoqi Wan wanyaoqi@yunionyun.com"

View File

@@ -54,7 +54,7 @@ type ImageOptionalOptions struct {
OsDist string `help:"Distribution name of OS" metavar:"OS_DISTRIBUTION"`
OsVersion string `help:"Version of OS"`
OsCodename string `help:"Codename of OS"`
OsArch string `help:"Os hardware architecture" choices:"x86|x86_64|aarch32|aarch64"`
OsArch string `help:"Os hardware architecture" choices:"x86|x86_64|aarch32|aarch64|riscv32|riscv64"`
OsLang string `help:"OS Language" choices:"zh_CN|en_US"`
Preference int64 `help:"Disk preferences"`
Notes string `help:"Notes about the image"`

View File

@@ -265,7 +265,7 @@ const (
VM_MACHINE_TYPE_PC = "pc"
VM_MACHINE_TYPE_Q35 = "q35"
VM_MACHINE_TYPE_ARM_VIRT = "virt"
VM_MACHINE_TYPE_VIRT = "virt"
VM_VDI_PROTOCOL_VNC = "vnc"
VM_VDI_PROTOCOL_SPICE = "spice"

View File

@@ -151,14 +151,16 @@ const (
const (
OS_ARCH_ALL = "all"
OS_ARCH_X86 = "x86"
OS_ARCH_ARM = "arm"
OS_ARCH_X86 = "x86"
OS_ARCH_ARM = "arm"
OS_ARCH_RISCV = "riscv"
OS_ARCH_I386 = "i386"
OS_ARCH_X86_32 = "x86_32"
OS_ARCH_X86_64 = "x86_64"
OS_ARCH_AARCH32 = "aarch32"
OS_ARCH_AARCH64 = "aarch64"
OS_ARCH_RISCV32 = "riscv32"
OS_ARCH_RISCV64 = "riscv64"
)
@@ -174,6 +176,11 @@ var (
OS_ARCH_AARCH32,
OS_ARCH_AARCH64,
}
ARCH_RISCV = []string{
OS_ARCH_RISCV,
OS_ARCH_RISCV32,
OS_ARCH_RISCV64,
}
)
func IsARM(osArch string) bool {
@@ -184,6 +191,10 @@ func IsX86(osArch string) bool {
return utils.IsInStringArray(osArch, ARCH_X86)
}
func IsRISCV(osArch string) bool {
return utils.IsInStringArray(osArch, ARCH_RISCV)
}
func IsIllegalSearchDomain(domain string) bool {
switch domain {
case "cloud.onecloud.io":
@@ -202,5 +213,8 @@ func IsSameArch(arch1, arch2 string) bool {
if IsX86(arch1) && IsX86(arch2) {
return true
}
if IsRISCV(arch1) && IsRISCV(arch2) {
return true
}
return false
}

View File

@@ -62,6 +62,12 @@ func ListQueryByArchitecture(q *sqlchemy.SQuery, fieldKey string, archs []string
sqlchemy.Equals(q.Field(fieldKey), apis.OS_ARCH_AARCH32),
sqlchemy.Equals(q.Field(fieldKey), apis.OS_ARCH_AARCH64),
))
} else if arch == apis.OS_ARCH_RISCV {
conditions = append(conditions, sqlchemy.OR(
sqlchemy.Startswith(q.Field(fieldKey), arch),
sqlchemy.Equals(q.Field(fieldKey), apis.OS_ARCH_RISCV32),
sqlchemy.Equals(q.Field(fieldKey), apis.OS_ARCH_RISCV64),
))
} else {
conditions = append(conditions, sqlchemy.Startswith(q.Field(fieldKey), arch))
}

View File

@@ -1005,8 +1005,8 @@ func (self *SKVMGuestDriver) validateVGA(ovdi, ovga string, nvdi, nvga *string)
func (self *SKVMGuestDriver) validateMachineType(machine string, osArch string) error {
var candidate []string
if apis.IsARM(osArch) {
candidate = []string{api.VM_MACHINE_TYPE_ARM_VIRT}
if apis.IsARM(osArch) || apis.IsRISCV(osArch) {
candidate = []string{api.VM_MACHINE_TYPE_VIRT}
} else {
candidate = []string{api.VM_MACHINE_TYPE_PC, api.VM_MACHINE_TYPE_Q35}
}
@@ -1311,8 +1311,8 @@ func (kvm *SKVMGuestDriver) ValidateGuestHotChangeConfigInput(ctx context.Contex
if guest.GetMetadata(ctx, api.VM_METADATA_HOTPLUG_CPU_MEM, nil) != "enable" {
return confs, errors.Wrap(errors.ErrInvalidStatus, "host plug cpu memory is disabled")
}
if apis.IsARM(guest.OsArch) {
return confs, errors.Wrap(errors.ErrInvalidStatus, "cpu architecture is arm")
if apis.IsARM(guest.OsArch) || apis.IsRISCV(guest.OsArch) {
return confs, errors.Wrapf(errors.ErrInvalidStatus, "cpu architecture is %s", guest.OsArch)
}
return confs, nil
}

View File

@@ -1627,6 +1627,8 @@ func (self *SDisk) GetMasterHost(storage *SStorage) (*SHost, error) {
q = q.In("cpu_architecture", apis.ARCH_X86)
case apis.OS_ARCH_ARM:
q = q.In("cpu_architecture", apis.ARCH_ARM)
case apis.OS_ARCH_RISCV:
q = q.In("cpu_architecture", apis.ARCH_RISCV)
}
}
host := SHost{}

View File

@@ -207,7 +207,7 @@ func (self *SGuest) PerformSaveImage(ctx context.Context, userCred mcclient.Toke
input.OsType = "Linux"
}
input.OsArch = self.OsArch
if apis.IsARM(self.OsArch) {
if apis.IsARM(self.OsArch) || apis.IsRISCV(self.OsArch) {
if osArch := self.GetMetadata(ctx, "os_arch", nil); len(osArch) == 0 {
host, _ := self.GetHost()
input.OsArch = host.CpuArchitecture
@@ -293,7 +293,7 @@ func (self *SGuest) PerformSaveGuestImage(ctx context.Context, userCred mcclient
}
kwargs.Properties["os_type"] = osType
if apis.IsARM(self.OsArch) {
if apis.IsARM(self.OsArch) || apis.IsRISCV(self.OsArch) {
var osArch string
if osArch = self.GetMetadata(ctx, "os_arch", nil); len(osArch) == 0 {
host, _ := self.GetHost()

View File

@@ -1808,8 +1808,11 @@ func (manager *SGuestManager) validateCreateData(
}
}
if arch := imgProperties["os_arch"]; strings.Contains(arch, "aarch") || strings.Contains(arch, "arm") {
arch := imgProperties["os_arch"]
if strings.Contains(arch, "aarch") || strings.Contains(arch, "arm") {
input.OsArch = apis.OS_ARCH_AARCH64
} else if strings.Contains(arch, "riscv") {
input.OsArch = apis.OS_ARCH_RISCV64
}
// enable tpm on windows 11 image
@@ -1840,7 +1843,7 @@ func (manager *SGuestManager) validateCreateData(
imgSupportBIOS = &supportBIOS
}
if input.OsArch == apis.OS_ARCH_AARCH64 {
if apis.IsARM(input.OsArch) || apis.IsRISCV(input.OsArch) {
// arm image supports UEFI by default
support := true
imgSupportUEFI = &support

View File

@@ -985,6 +985,10 @@ func (hh *SHost) IsArmHost() bool {
return hh.CpuArchitecture == apis.OS_ARCH_AARCH64
}
func (hh *SHost) IsRISCVHost() bool {
return hh.CpuArchitecture == apis.OS_ARCH_RISCV64
}
func (hh *SHost) GetZone() (*SZone, error) {
zone, err := ZoneManager.FetchById(hh.ZoneId)
if err != nil {

View File

@@ -781,6 +781,13 @@ func (manager *SServerSkuManager) ListItemFilter(
sqlchemy.Equals(q.Field("cpu_arch"), apis.OS_ARCH_AARCH64),
sqlchemy.IsNullOrEmpty(q.Field("cpu_arch")),
))
} else if arch == apis.OS_ARCH_RISCV {
conditions = append(conditions, sqlchemy.OR(
sqlchemy.Startswith(q.Field("cpu_arch"), arch),
sqlchemy.Equals(q.Field("cpu_arch"), apis.OS_ARCH_RISCV32),
sqlchemy.Equals(q.Field("cpu_arch"), apis.OS_ARCH_RISCV64),
sqlchemy.IsNullOrEmpty(q.Field("cpu_arch")),
))
} else {
conditions = append(conditions, sqlchemy.Startswith(q.Field("cpu_arch"), arch))
}

View File

@@ -47,10 +47,14 @@ var (
QEMU_KVM_PATH = "/usr/libexec/qemu-kvm"
OS_ARCH_AARCH64 = "aarch64"
ARM_INITRD_PATH = "/yunionos/aarch64/initramfs"
ARM_KERNEL_PATH = "/yunionos/aarch64/kernel"
X86_INITRD_PATH = "/yunionos/x86_64/initramfs"
X86_KERNEL_PATH = "/yunionos/x86_64/kernel"
OS_ARCH_RISCV64 = "riscv64"
ARM_INITRD_PATH = "/yunionos/aarch64/initramfs"
ARM_KERNEL_PATH = "/yunionos/aarch64/kernel"
X86_INITRD_PATH = "/yunionos/x86_64/initramfs"
X86_KERNEL_PATH = "/yunionos/x86_64/kernel"
RISCV_INITRD_PATH = "/yunionos/riscv64/initramfs"
RISCV_KERNEL_PATH = "/yunionos/riscv64/kernel"
RUN_ON_HOST_ROOT_PATH = "/opt/cloud/host-deployer"
@@ -102,6 +106,14 @@ func (m *QemuDeployManager) GetARMInitrdPath() string {
}
}
func (m *QemuDeployManager) GetRISCVInitrdPath() string {
if m.runOnHost() {
return path.Join(RUN_ON_HOST_ROOT_PATH, RISCV_INITRD_PATH)
} else {
return RISCV_INITRD_PATH
}
}
func (m *QemuDeployManager) GetX86KernelPath() string {
if m.runOnHost() {
return path.Join(RUN_ON_HOST_ROOT_PATH, X86_KERNEL_PATH)
@@ -118,6 +130,14 @@ func (m *QemuDeployManager) GetARMKernelPath() string {
}
}
func (m *QemuDeployManager) GetRISCVKernelPath() string {
if m.runOnHost() {
return path.Join(RUN_ON_HOST_ROOT_PATH, RISCV_KERNEL_PATH)
} else {
return RISCV_KERNEL_PATH
}
}
func (m *QemuDeployManager) Acquire() {
log.Infof("acquire QemuDeployManager")
m.c <- struct{}{}
@@ -202,6 +222,8 @@ func InitQemuDeployManager(
if cpuArch == OS_ARCH_AARCH64 {
qemutils.UseAarch64()
} else if cpuArch == OS_ARCH_RISCV64 {
qemutils.UseRiscv64()
}
var qemuCmd string
@@ -598,6 +620,7 @@ func (d *QemuBaseDriver) CleanGuest() {
if d.pidPath != "" && fileutils2.Exists(d.pidPath) {
pid, _ := fileutils2.FileGetContents(d.pidPath)
pid = strings.TrimSpace(pid)
if len(pid) > 0 {
out, err := procutils.NewCommand("kill", pid).Output()
log.Infof("kill process %s %v", out, err)
@@ -674,7 +697,9 @@ func (d *QemuBaseDriver) startCmds(
}
cmd += diskDrive
cmd += __("-device scsi-hd,drive=drive_%d,bus=scsi.0,id=drive_%d,serial=%s", i, i, strings.ReplaceAll(diskIds[i], "-", ""))
serialId := strings.ReplaceAll(diskIds[i], "-", "")
deviceId := serialId[:20]
cmd += __("-device scsi-hd,drive=drive_%d,bus=scsi.0,id=drive_%d,serial=%s,device_id=%s", i, i, serialId, deviceId)
}
cmd += __("-drive id=cd0,if=none,media=cdrom,file=%s", DEPLOY_ISO)
cmd += cdromDeviceOpts
@@ -801,6 +826,63 @@ func (d *QemuARMDriver) StartGuest(sshPort, ncpu, memSizeMB int, hugePage bool,
return nil
}
type QemuRISCVDriver struct {
QemuBaseDriver
}
func (d *QemuRISCVDriver) StartGuest(sshPort, ncpu, memSizeMB int, hugePage bool, pageSizeKB int, imageInfo qemuimg.SImageInfo, disksPath, diskIds []string) error {
uuid := stringutils.UUID4()
socketPath := fmt.Sprintf("/opt/cloud/host-deployer/hmp_%s.socket", uuid)
d.pidPath = fmt.Sprintf("/opt/cloud/host-deployer/%s.pid", uuid)
machineOpts := __("-M virt")
cdromDeviceOpts := __("-device scsi-cd,drive=cd0,share-rw=true")
fwOpts := ""
cmd := d.startCmds(
sshPort,
ncpu,
memSizeMB,
imageInfo,
disksPath,
diskIds,
machineOpts,
cdromDeviceOpts,
fwOpts,
socketPath,
manager.GetRISCVInitrdPath(),
manager.GetRISCVKernelPath(),
)
log.Infof("start guest %s", cmd)
out, err := manager.startQemu(cmd)
if err != nil {
log.Errorf("failed start guest %s: %s", out, err)
return errors.Wrapf(err, "failed start guest %s", out)
}
var c = make(chan error)
onMonitorConnected := func() {
log.Infof("monitor connected")
c <- nil
}
onMonitorDisConnect := func(e error) {
log.Errorf("monitor disconnect %s", e)
}
onMonitorConnectFailed := func(e error) {
log.Errorf("monitor connect failed %s", e)
c <- e
}
m := monitor.NewHmpMonitor("", "", onMonitorDisConnect, onMonitorConnectFailed, onMonitorConnected)
if err = m.ConnectWithSocket(socketPath); err != nil {
return errors.Wrapf(err, "connect socket %s failed", socketPath)
}
if err = <-c; err != nil {
return errors.Wrap(err, "monitor connect failed")
}
d.hmp = m
return nil
}
type IQemuArchDriver interface {
StartGuest(sshPort, ncpu, memSizeMB int, hugePage bool, pageSizeKB int, imageInfo qemuimg.SImageInfo, disksPath, diskIds []string) error
CleanGuest()
@@ -809,6 +891,8 @@ type IQemuArchDriver interface {
func NewCpuArchDriver(cpuArch string) IQemuArchDriver {
if cpuArch == OS_ARCH_AARCH64 {
return &QemuARMDriver{}
} else if cpuArch == OS_ARCH_RISCV64 {
return &QemuRISCVDriver{}
}
return &QemuX86Driver{}

View File

@@ -578,6 +578,11 @@ func (l *sLinuxRootFs) GetArch(rootFs IDiskPartition) string {
return apis.OS_ARCH_AARCH64
case elf.EM_ARM:
return apis.OS_ARCH_AARCH32
case elf.EM_RISCV:
if elfHeader.Class == elf.ELFCLASS32 {
return apis.OS_ARCH_RISCV32
}
return apis.OS_ARCH_RISCV64
}
}
}

View File

@@ -14,11 +14,16 @@
package arch
import "yunion.io/x/onecloud/pkg/hostman/guestman/desc"
import (
"fmt"
"yunion.io/x/onecloud/pkg/hostman/guestman/desc"
)
const (
Arch_x86_64 string = "x86_64"
Arch_aarch64 string = "aarch64"
Arch_riscv64 string = "riscv64"
)
type Arch interface {
@@ -50,6 +55,8 @@ func NewArch(arch string) Arch {
return &X86{}
case Arch_aarch64:
return &ARM{}
case Arch_riscv64:
return &RISCV{}
}
return nil
}
@@ -87,3 +94,24 @@ func (*archBase) GeneratePvpanicDesc() *desc.SGuestPvpanic {
func (*archBase) GenerateIsaSerialDesc() *desc.SGuestIsaSerial {
return nil
}
type otherArchBase struct {
}
// -device scsi-cd,drive=cd0,share-rw=true
// if=none,file=%s,id=cd0,media=cdrom
func (*otherArchBase) GenerateCdromDesc(osName string, cdrom *desc.SGuestCdrom) {
id := fmt.Sprintf("scsi%d-cd0", cdrom.Ordinal)
scsiDev := desc.NewScsiDevice("", "scsi-cd", id)
scsiDev.Options = map[string]string{"share-rw": "true"}
driveOptions := map[string]string{
"if": "none",
"media": "cdrom",
}
cdrom.Scsi = scsiDev
cdrom.DriveOptions = driveOptions
cdrom.Id = id
}
func (*otherArchBase) GenerateFloppyDesc(osName string, floppy *desc.SGuestFloppy) {
}

View File

@@ -15,8 +15,6 @@
package arch
import (
"fmt"
"yunion.io/x/onecloud/pkg/hostman/guestman/desc"
"yunion.io/x/onecloud/pkg/hostman/options"
)
@@ -34,25 +32,7 @@ var ARM_MAX_MEM_MB uint = 262144
type ARM struct {
archBase
}
// -device scsi-cd,drive=cd0,share-rw=true
// if=none,file=%s,id=cd0,media=cdrom
func (*ARM) GenerateCdromDesc(osName string, cdrom *desc.SGuestCdrom) {
id := fmt.Sprintf("scsi%d-cd0", cdrom.Ordinal)
scsiDev := desc.NewScsiDevice("", "scsi-cd", id)
scsiDev.Options = map[string]string{"share-rw": "true"}
driveOptions := map[string]string{
"if": "none",
"media": "cdrom",
}
cdrom.Scsi = scsiDev
cdrom.DriveOptions = driveOptions
cdrom.Id = id
}
func (*ARM) GenerateFloppyDesc(osName string, floppy *desc.SGuestFloppy) {
otherArchBase
}
func (*ARM) GenerateMachineDesc(accel string) *desc.SGuestMachine {

View File

@@ -0,0 +1,75 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package arch
import (
"yunion.io/x/onecloud/pkg/hostman/guestman/desc"
"yunion.io/x/onecloud/pkg/hostman/options"
)
const (
RISCV_MAX_CPUS = 128
RISCV_SOCKETS = 1
RISCV_THREADS = 1
RISCV_MEM_DEFAULT_SLOTS = 4
)
var RISCV_MAX_MEM_MB uint = 262144
type RISCV struct {
archBase
otherArchBase
}
func (*RISCV) GenerateMachineDesc(accel string) *desc.SGuestMachine {
return &desc.SGuestMachine{
Accel: accel,
}
}
func (*RISCV) GenerateMemDesc() *desc.SGuestMem {
return &desc.SGuestMem{
Slots: RISCV_MEM_DEFAULT_SLOTS,
MaxMem: RISCV_MAX_MEM_MB,
}
}
func (*RISCV) GenerateCpuDesc(cpus uint, cpuMax uint, s KVMGuestInstance) (*desc.SGuestCpu, error) {
var hostCPUPassthrough = options.HostOptions.HostCpuPassthrough
var accel, cpuType string
if s.IsKvmSupport() {
accel = "kvm"
if hostCPUPassthrough {
cpuType = "host"
} else {
// * under KVM, -cpu max is the same as -cpu host
// * under TCG, -cpu max means "emulate with as many features as possible"
cpuType = "max"
}
} else {
accel = "tcg"
cpuType = "max"
}
return &desc.SGuestCpu{
Cpus: cpus,
Sockets: RISCV_SOCKETS,
Cores: cpuMax / RISCV_SOCKETS / RISCV_THREADS,
Threads: RISCV_THREADS,
MaxCpus: cpuMax,
Model: cpuType,
Accel: accel,
}, nil
}

View File

@@ -210,10 +210,19 @@ func (m *SGuestManager) startContainerSyncLoop() {
}
}
func (m *SGuestManager) getMachineVirtMaxCpus() uint {
if m.host.IsAarch64() {
return arch.ARM_MAX_CPUS
} else if m.host.IsRiscv64() {
return arch.RISCV_MAX_CPUS
}
return 0
}
func (m *SGuestManager) InitQemuMaxCpus(machineCaps []monitor.MachineInfo, kvmMaxCpus uint) {
m.qemuMachineCpuMax[compute.VM_MACHINE_TYPE_PC] = arch.X86_MAX_CPUS
m.qemuMachineCpuMax[compute.VM_MACHINE_TYPE_Q35] = arch.X86_MAX_CPUS
m.qemuMachineCpuMax[compute.VM_MACHINE_TYPE_ARM_VIRT] = arch.ARM_MAX_CPUS
m.qemuMachineCpuMax[compute.VM_MACHINE_TYPE_VIRT] = m.getMachineVirtMaxCpus()
if len(machineCaps) == 0 {
return
}
@@ -259,6 +268,11 @@ func (m *SGuestManager) InitQemuMaxMems(maxMems uint) {
arch.ARM_MAX_MEM_MB = maxMems
}
}
if m.host.IsRiscv64() {
if maxMems > arch.RISCV_MAX_MEM_MB {
arch.RISCV_MAX_MEM_MB = maxMems
}
}
}
func (m *SGuestManager) InitPythonPath() error {

View File

@@ -456,11 +456,11 @@ func (s *SKVMGuestInstance) initGuestDisks(pciRoot, pciBridge *desc.PCIControlle
func (s *SKVMGuestInstance) fixDiskDriver() (bool, bool, bool) {
var virtioScsi, pvScsi, sataDisk = false, false, false
isArm := s.manager.host.IsAarch64()
isX86 := s.manager.host.IsX8664()
osname := s.GetOsName()
for i := 0; i < len(s.Desc.Disks); i++ {
if isArm && (s.Desc.Disks[i].Driver == DISK_DRIVER_IDE ||
if !isX86 && (s.Desc.Disks[i].Driver == DISK_DRIVER_IDE ||
s.Desc.Disks[i].Driver == DISK_DRIVER_SATA) {
s.Desc.Disks[i].Driver = DISK_DRIVER_SCSI
} else if osname == OS_NAME_MACOS {
@@ -485,10 +485,10 @@ func (s *SKVMGuestInstance) initVirtioSerial(pciRoot *desc.PCIController) {
}
func (s *SKVMGuestInstance) initGuestVga(pciRoot *desc.PCIController) {
var isAarch64 = s.manager.host.IsAarch64()
var isNotX86 = !s.manager.host.IsX8664()
if s.gpusHasVga() {
s.Desc.Vga = "none"
} else if isAarch64 {
} else if isNotX86 {
s.Desc.Vga = "virtio-gpu"
} else if s.Desc.Vga == "" {
s.Desc.Vga = "std"

View File

@@ -122,6 +122,8 @@ func NewKVMGuestInstance(id string, manager *SGuestManager) *SKVMGuestInstance {
qemuArch := arch.Arch_x86_64
if manager.host.IsAarch64() {
qemuArch = arch.Arch_aarch64
} else if manager.host.IsRiscv64() {
qemuArch = arch.Arch_riscv64
}
return &SKVMGuestInstance{
SKVMInstanceRuntime: SKVMInstanceRuntime{
@@ -631,6 +633,8 @@ func (s *SKVMGuestInstance) isSelfCmdline(cmdline, uuid string) bool {
func (s *SKVMGuestInstance) GetRescueDirPath() string {
if s.manager.host.IsAarch64() {
return path.Join("/opt/cloud/host-deployer/yunionos/aarch64")
} else if s.manager.host.IsRiscv64() {
return path.Join("/opt/cloud/host-deployer/yunionos/riscv64")
} else {
return path.Join("/opt/cloud/host-deployer/yunionos/x86_64")
}
@@ -1373,7 +1377,7 @@ func (s *SKVMGuestInstance) syncStatusUnsync(reason string) {
func (s *SKVMGuestInstance) collectGuestDescription() error {
var cpuList []monitor.HotpluggableCPU
var err error
if !s.manager.host.IsAarch64() {
if s.manager.host.IsX8664() {
cpuList, err = s.getHotpluggableCPUList()
if err != nil {
return errors.Wrap(err, "get hotpluggable cpus")

View File

@@ -267,12 +267,12 @@ func (s *SKVMGuestInstance) isQ35() bool {
}
func (s *SKVMGuestInstance) isVirt() bool {
return s.getMachine() == api.VM_MACHINE_TYPE_ARM_VIRT
return s.getMachine() == api.VM_MACHINE_TYPE_VIRT
}
func (s *SKVMGuestInstance) isPcie() bool {
return utils.IsInStringArray(s.getMachine(),
[]string{api.VM_MACHINE_TYPE_Q35, api.VM_MACHINE_TYPE_ARM_VIRT})
[]string{api.VM_MACHINE_TYPE_Q35, api.VM_MACHINE_TYPE_VIRT})
}
func (s *SKVMGuestInstance) GetVdiProtocol() string {
@@ -398,6 +398,8 @@ func (s *SKVMGuestInstance) generateStartScript(data *jsonutils.JSONDict) (strin
// inject qemu arch
if s.manager.host.IsAarch64() {
input.QemuArch = qemu.Arch_aarch64
} else if s.manager.host.IsRiscv64() {
input.QemuArch = qemu.Arch_riscv64
} else {
input.QemuArch = qemu.Arch_x86_64
}
@@ -546,7 +548,7 @@ function start_swtpm() {
}
// inject usb devices
if input.QemuArch == qemu.Arch_aarch64 {
if !input.QemuArch.IsX86() {
input.Devices = append(input.Devices,
fmt.Sprintf("usb-tablet,id=input0,bus=%s.0,port=1", s.Desc.Usb.Id),
fmt.Sprintf("usb-kbd,id=input1,bus=%s.0,port=2", s.Desc.Usb.Id),
@@ -1332,12 +1334,14 @@ func (s *SKVMGuestInstance) fixGuestMachineType() {
s.Desc.Machine = api.VM_MACHINE_TYPE_Q35
s.Desc.Bios = qemu.BIOS_UEFI
}
if s.manager.host.IsAarch64() {
if !s.manager.host.IsX8664() {
if utils.IsInStringArray(s.Desc.Machine, []string{
"", api.VM_MACHINE_TYPE_PC, api.VM_MACHINE_TYPE_Q35,
}) {
s.Desc.Machine = api.VM_MACHINE_TYPE_ARM_VIRT
s.Desc.Machine = api.VM_MACHINE_TYPE_VIRT
}
}
if s.manager.host.IsAarch64() || s.manager.host.IsRiscv64() {
s.Desc.Bios = qemu.BIOS_UEFI
}
}
@@ -1384,7 +1388,7 @@ func (s *SKVMGuestInstance) initTpmDesc() {
}
func (s *SKVMGuestInstance) getVfioDeviceHotPlugPciControllerType() *desc.PCI_CONTROLLER_TYPE {
if s.Desc.Machine == api.VM_MACHINE_TYPE_Q35 || s.Desc.Machine == api.VM_MACHINE_TYPE_ARM_VIRT {
if s.Desc.Machine == api.VM_MACHINE_TYPE_Q35 || s.Desc.Machine == api.VM_MACHINE_TYPE_VIRT {
_, _, found := s.findUnusedSlotForController(desc.CONTROLLER_TYPE_PCIE_ROOT_PORT, 0)
if found {
var contType desc.PCI_CONTROLLER_TYPE = desc.CONTROLLER_TYPE_PCIE_ROOT_PORT
@@ -1428,12 +1432,12 @@ func (s *SKVMGuestInstance) getDiskBootOrderType(driver string) uefi.OvmfDeviceP
case qemu.DISK_DRIVER_SCSI, qemu.DISK_DRIVER_PVSCSI:
return uefi.DEVICE_TYPE_SCSI
case qemu.DISK_DRIVER_IDE:
if s.manager.host.IsAarch64() {
if !s.manager.host.IsX8664() {
return uefi.DEVICE_TYPE_SCSI
}
return uefi.DEVICE_TYPE_IDE
case qemu.DISK_DRIVER_SATA:
if s.manager.host.IsAarch64() {
if !s.manager.host.IsX8664() {
return uefi.DEVICE_TYPE_SCSI
}
return uefi.DEVICE_TYPE_SATA
@@ -1442,7 +1446,7 @@ func (s *SKVMGuestInstance) getDiskBootOrderType(driver string) uefi.OvmfDeviceP
}
func (s *SKVMGuestInstance) getCdromBootOrder() uefi.OvmfDevicePathType {
if s.manager.host.IsAarch64() {
if !s.manager.host.IsX8664() {
return uefi.DEVICE_TYPE_SCSI_CDROM
}
return uefi.DEVICE_TYPE_CDROM

View File

@@ -362,7 +362,9 @@ func getDiskDeviceOption(optDrv QemuOptions, disk *desc.SGuestDisk, osName strin
var opt = ""
opt += GetDiskDeviceModel(diskDriver)
if osName != OS_NAME_VMWARE {
opt += fmt.Sprintf(",serial=%s", strings.ReplaceAll(disk.DiskId, "-", ""))
serial := strings.ReplaceAll(disk.DiskId, "-", "")
opt += fmt.Sprintf(",serial=%s", serial)
opt += optDrv.ScsiDeviceId(serial)
}
opt += fmt.Sprintf(",drive=drive_%d", diskIndex)
if diskDriver == DISK_DRIVER_VIRTIO {
@@ -893,7 +895,7 @@ func GenerateStartOptions(
opts = append(opts, nicOpts...)
if !input.GuestDesc.LightMode {
if input.QemuArch == Arch_aarch64 {
if !input.QemuArch.IsX86() {
if input.GuestDesc.Usb != nil {
opts = append(opts, generatePCIDeviceOption(input.GuestDesc.Usb.PCIDevice))
for _, device := range input.Devices {

View File

@@ -35,6 +35,8 @@ const (
Version_4_0_1 Version = "4.0.1"
Version_2_12_1 Version = "2.12.1"
Version_9_0_1 Version = "9.0.1"
Version_10_0_3 Version = "10.0.3"
Version_10_0_7 Version = "10.0.7"
)
type Arch string
@@ -42,8 +44,13 @@ type Arch string
const (
Arch_x86_64 Arch = "x86_64"
Arch_aarch64 Arch = "aarch64"
Arch_riscv64 Arch = "riscv64"
)
func (a Arch) IsX86() bool {
return a == Arch_x86_64
}
const (
OS_NAME_LINUX = "Linux"
OS_NAME_WINDOWS = "Windows"
@@ -110,6 +117,7 @@ type QemuOptions interface {
VNC(port uint, usePasswd bool) string
Initrd(initrdPath string) string
Kernel(kernelPath string) string
ScsiDeviceId(serial string) string
}
var (
@@ -218,6 +226,10 @@ func (o baseOptions) Nodefconfig() string {
return "-nodefconfig"
}
func (o baseOptions) ScsiDeviceId(serial string) string {
return fmt.Sprintf(",device_id=%s", serial[:20])
}
/*
@subsection -no-kvm-pit-reinjection (since 1.3.0)
@@ -407,3 +419,21 @@ func (o baseOptions_aarch64) Global() string {
func (o baseOptions_aarch64) NoHpet() (bool, string) {
return false, ""
}
type baseOptions_riscv64 struct {
*baseOptions
}
func newBaseOptions_riscv64() *baseOptions_riscv64 {
return &baseOptions_riscv64{
baseOptions: newBaseOptions(Arch_riscv64),
}
}
func (o baseOptions_riscv64) Global() string {
return ""
}
func (o baseOptions_riscv64) NoHpet() (bool, string) {
return false, ""
}

View File

@@ -0,0 +1,27 @@
package qemu
func init() {
RegisterCmd(
newCmd_10_0_3_riscv64(),
)
}
type opt_1003_riscv64 struct {
*baseOptions_riscv64
*baseOptions_ge_310
}
func newCmd_10_0_3_riscv64() QemuCommand {
return newBaseCommand(
Version_10_0_3,
Arch_riscv64,
newOpt_10_0_3_riscv64(),
)
}
func newOpt_10_0_3_riscv64() QemuOptions {
return &opt_1003_riscv64{
baseOptions_riscv64: newBaseOptions_riscv64(),
baseOptions_ge_310: newBaseOptionsGE310(),
}
}

View File

@@ -0,0 +1,71 @@
package qemu
func init() {
RegisterCmd(
newCmd_10_0_7_x86_64(),
newCmd_10_0_7_aarch64(),
newCmd_10_0_7_riscv64(),
)
}
type opt_1007_x86_64 struct {
*baseOptions_x86_64
*baseOptions_ge_310
*baseOptions_ge_800_x86_64
}
func newOpt_10_0_7_x86_64() QemuOptions {
return &opt_1007_x86_64{
baseOptions_x86_64: newBaseOptions_x86_64(),
baseOptions_ge_800_x86_64: newBaseOptionsGE800_x86_64(),
baseOptions_ge_310: newBaseOptionsGE310(),
}
}
func newCmd_10_0_7_x86_64() QemuCommand {
return newBaseCommand(
Version_10_0_7,
Arch_x86_64,
newOpt_10_0_7_x86_64(),
)
}
type opt_1007_aarch64 struct {
*baseOptions_aarch64
*baseOptions_ge_310
}
func newCmd_10_0_7_aarch64() QemuCommand {
return newBaseCommand(
Version_10_0_7,
Arch_aarch64,
newOpt_10_0_7_aarch64(),
)
}
func newOpt_10_0_7_aarch64() QemuOptions {
return &opt_1007_aarch64{
baseOptions_aarch64: newBaseOptions_aarch64(),
baseOptions_ge_310: newBaseOptionsGE310(),
}
}
type opt_1007_riscv64 struct {
*baseOptions_riscv64
*baseOptions_ge_310
}
func newCmd_10_0_7_riscv64() QemuCommand {
return newBaseCommand(
Version_10_0_7,
Arch_riscv64,
newOpt_10_0_7_riscv64(),
)
}
func newOpt_10_0_7_riscv64() QemuOptions {
return &opt_1007_riscv64{
baseOptions_riscv64: newBaseOptions_riscv64(),
baseOptions_ge_310: newBaseOptionsGE310(),
}
}

View File

@@ -33,16 +33,34 @@ type opt_2121_x86_64 struct {
*baseOptions_x86_64
}
func (o opt_2121_x86_64) ScsiDeviceId(serial string) string {
return ""
}
func newOpt_2_12_1_x86_64() QemuOptions {
return &opt_2121_x86_64{
baseOptions_x86_64: newBaseOptions_x86_64(),
}
}
type opt_2121_aarch64 struct {
*baseOptions_aarch64
}
func (o opt_2121_aarch64) ScsiDeviceId(serial string) string {
return ""
}
func newOpt_2_12_1_aarch64() QemuOptions {
return &opt_2121_aarch64{
baseOptions_aarch64: newBaseOptions_aarch64(),
}
}
func newCmd_2_12_1_aarch64() QemuCommand {
return newBaseCommand(
Version_2_12_1,
Arch_aarch64,
newBaseOptions_aarch64(),
newOpt_2_12_1_aarch64(),
)
}

View File

@@ -38,7 +38,7 @@ type SDeployOptions struct {
HugepagesOption string `help:"Hugepages option: disable|native|transparent" default:"transparent"`
HugepageSizeMb int `help:"hugepage size mb default 1G" default:"1024"`
// DefaultQemuVersion string `help:"Default qemu version" default:"4.2.0"`
DeployGuestMemSizeMb int `help:"Deploy guest mem size mb" default:"320"`
DeployGuestMemSizeMb int `help:"Deploy guest mem size mb" default:"512"`
ListenInterface string `help:"Master address of host server"`
Networks []string `help:"Network interface information"`

View File

@@ -2722,7 +2722,7 @@ func (h *SHostInfo) IsAarch64() bool {
return h.GetCpuArchitecture() == apis.OS_ARCH_AARCH64
}
func (h *SHostInfo) IsRiscV() bool {
func (h *SHostInfo) IsRiscv64() bool {
return h.GetCpuArchitecture() == apis.OS_ARCH_RISCV64
}
@@ -2848,8 +2848,8 @@ func NewHostInfo() (*SHostInfo, error) {
if res.IsAarch64() {
qemutils.UseAarch64()
} else if res.IsRiscV() {
qemutils.UseRiscV()
} else if res.IsRiscv64() {
qemutils.UseRiscv64()
} else if !res.IsX8664() {
return nil, fmt.Errorf("unsupport cpu architecture %s", cpu.CpuArchitecture)
}

View File

@@ -73,6 +73,7 @@ type IHost interface {
GetKernelVersion() string
IsAarch64() bool
IsX8664() bool
IsRiscv64() bool
GetHostTopology() *hostapi.HostTopology
GetReservedCpusInfo() (*cpuset.CPUSet, *cpuset.CPUSet)
GetReservedMemMb() int

View File

@@ -39,7 +39,7 @@ type SHostBaseOptions struct {
LiveMigrateCpuThrottleInitial int64 `default:"60" help:"live migrate auto convert cpu throttle initial"`
LiveMigrateCpuThrottleIncrement int64 `default:"20" help:"live migrate auto convert cpu throttle increment"`
DefaultQemuVersion string `help:"Default qemu version" default:"4.2.0"`
DefaultQemuVersion string `help:"Default qemu version" default:"10.0.7"`
NoHpet bool `help:"Disable qemu hpet timer" default:"true"`
CdromCount int `help:"cdrom count" default:"1"`

View File

@@ -443,7 +443,7 @@ func (o *ScopedResourceListOptions) Params() (*jsonutils.JSONDict, error) {
}
type MultiArchListOptions struct {
OsArch string `help:"Filter resource by arch" choices:"i386|x86|x86_32|x86_64|arm|aarch32|aarch64"`
OsArch string `help:"Filter resource by arch" choices:"i386|x86|x86_32|x86_64|arm|aarch32|aarch64|riscv|riscv32|riscv64"`
}
func (o *MultiArchListOptions) Params() (*jsonutils.JSONDict, error) {

View File

@@ -61,15 +61,20 @@ func (f *CPUPredicate) Execute(ctx context.Context, u *core.Unit, c core.Candida
archMatch := true
isArmHost := getter.IsArmHost()
isRiscvHost := getter.IsRISCVHost()
if d.Hypervisor != compute.HYPERVISOR_POD {
if apis.IsARM(d.OsArch) {
// process arm64 host
if !isArmHost {
archMatch = false
}
} else if apis.IsRISCV(d.OsArch) {
if !isRiscvHost {
archMatch = false
}
} else {
// process x86_64 host
if isArmHost {
if isArmHost || isRiscvHost {
archMatch = false
}
}

View File

@@ -93,6 +93,10 @@ func (b baseHostGetter) IsArmHost() bool {
return b.h.IsArmHost()
}
func (b baseHostGetter) IsRISCVHost() bool {
return b.h.IsRISCVHost()
}
func (b baseHostGetter) CPUArch() string {
return b.h.CpuArchitecture
}

View File

@@ -90,6 +90,7 @@ type CandidatePropertyGetter interface {
CPUArch() string
IsArmHost() bool
IsRISCVHost() bool
RunningCPUCount() int64
TotalCPUCount(useRsvd bool) int64
FreeCPUCount(useRsvd bool) int64

View File

@@ -314,6 +314,10 @@ func (m *MockCandidatePropertyGetter) IsArmHost() bool {
return false
}
func (m *MockCandidatePropertyGetter) IsRISCVHost() bool {
return false
}
func (m *MockCandidatePropertyGetter) CPUArch() string {
return ""
}

View File

@@ -39,7 +39,7 @@ func UseAarch64() {
qemuSystemCmd = "qemu-system-aarch64"
}
func UseRiscV() {
func UseRiscv64() {
qemuSystemCmd = "qemu-system-riscv64"
}