From bcc9394d67b33e5ba6ccb236d0e5001f636e4058 Mon Sep 17 00:00:00 2001 From: Manish Ranjan Mahanta Date: Fri, 20 Feb 2026 21:27:02 +0530 Subject: [PATCH] Adding support for ARM64 LCOW Signed-off-by: Manish Ranjan Mahanta --- cmd/runhcs/create-scratch.go | 8 ++++++++ internal/uvm/create_lcow.go | 28 ++++++++++++++++++++++++---- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/cmd/runhcs/create-scratch.go b/cmd/runhcs/create-scratch.go index 34a7500a5e..f28cb361b6 100644 --- a/cmd/runhcs/create-scratch.go +++ b/cmd/runhcs/create-scratch.go @@ -4,6 +4,7 @@ package main import ( gcontext "context" + "runtime" "github.com/Microsoft/hcsshim/internal/appargs" "github.com/Microsoft/hcsshim/internal/lcow" @@ -72,6 +73,13 @@ var createScratchCommand = cli.Command{ sizeGB = lcow.DefaultScratchSizeGB } + if runtime.GOARCH == "arm64" { + // Direct-boot is not supported on ARM64, so disable KernelDirect even if the flag is set. + opts.KernelDirect = false + // ARM64 doesn't support VPMem yet, so disable it even if the flag is set. + opts.VPMemDeviceCount = 0 + } + convertUVM, err := uvm.CreateLCOW(ctx, opts) if err != nil { return errors.Wrapf(err, "failed to create '%s'", opts.ID) diff --git a/internal/uvm/create_lcow.go b/internal/uvm/create_lcow.go index 5ac388b181..de481ef3ea 100644 --- a/internal/uvm/create_lcow.go +++ b/internal/uvm/create_lcow.go @@ -10,6 +10,7 @@ import ( "net" "os" "path/filepath" + "runtime" "strings" "github.com/Microsoft/go-winio" @@ -181,6 +182,12 @@ func NewDefaultOptionsLCOW(id, owner string) *OptionsLCOW { opts.UpdateBootFilesPath(context.TODO(), defaultLCOWOSBootFilesPath()) + if runtime.GOARCH == "arm64" { + // ARM64 doesn't support KernelDirect, so disable it even if the flag is set. + opts.KernelDirect = false + // ARM64 doesn't support VPMem yet, so disable it even if the flag is set. + opts.VPMemDeviceCount = 0 + } return opts } @@ -218,11 +225,12 @@ func (opts *OptionsLCOW) UpdateBootFilesPath(ctx context.Context, path string) { }).Debug("updated LCOW root filesystem to " + VhdFile) } - if opts.KernelDirect { + if opts.KernelDirect && runtime.GOARCH != "arm64" { // KernelDirect supports uncompressed kernel if the kernel is present. // Default to uncompressed if on box. NOTE: If `kernel` is already // uncompressed and simply named 'kernel' it will still be used // uncompressed automatically. + // ARM64 doesn't support KernelDirect, so skip this logic in that case. if _, err := os.Stat(filepath.Join(opts.BootFilesPath, UncompressedKernelFile)); err == nil { opts.KernelFile = UncompressedKernelFile @@ -807,14 +815,20 @@ func makeLCOWDoc(ctx context.Context, opts *OptionsLCOW, uvm *UtilityVM) (_ *hcs vmDebugging := false if opts.ConsolePipe != "" { vmDebugging = true - kernelArgs += " 8250_core.nr_uarts=1 8250_core.skip_txen_test=1 console=ttyS0,115200" + if runtime.GOARCH == "arm64" { + kernelArgs += " console=ttyAMA0,115200" + } else { + kernelArgs += " 8250_core.nr_uarts=1 8250_core.skip_txen_test=1 console=ttyS0,115200" + } doc.VirtualMachine.Devices.ComPorts = map[string]hcsschema.ComPort{ "0": { // Which is actually COM1 NamedPipe: opts.ConsolePipe, }, } } else { - kernelArgs += " 8250_core.nr_uarts=0" + if runtime.GOARCH != "arm64" { + kernelArgs += " 8250_core.nr_uarts=0" + } } if opts.EnableGraphicsConsole { @@ -835,7 +849,7 @@ func makeLCOWDoc(ctx context.Context, opts *OptionsLCOW, uvm *UtilityVM) (_ *hcs kernelArgs += " " + opts.KernelBootOptions } - if !opts.VPCIEnabled { + if runtime.GOARCH != "arm64" && !opts.VPCIEnabled { kernelArgs += ` pci=off` } @@ -967,6 +981,12 @@ func CreateLCOW(ctx context.Context, opts *OptionsLCOW) (_ *UtilityVM, err error return nil, errors.Wrap(err, errBadUVMOpts.Error()) } + // KernelDirect and VPMem devices are not supported by Hyper-V on ARM64. + if runtime.GOARCH == "arm64" { + opts.KernelDirect = false + opts.VPMemDeviceCount = 0 + } + // HCS config for SNP isolated vm is quite different to the usual case var doc *hcsschema.ComputeSystem if opts.SecurityPolicyEnabled {