Skip to content

Commit

Permalink
Merge pull request #34 from Code-Hex/add/mac-vm
Browse files Browse the repository at this point in the history
add macOS VM
  • Loading branch information
Code-Hex authored Aug 26, 2022
2 parents 2acf6bc + 6d4ae57 commit 8182bcf
Show file tree
Hide file tree
Showing 37 changed files with 2,625 additions and 18 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/compile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,6 @@ jobs:
with:
go-version: ${{ matrix.go }}
- name: Build
run: cd example && make
run: cd example/linux && make
- name: vet
run: go vet ./...
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ virtualization
*.log
.envrc
.env
RestoreImage.ipsw
118 changes: 118 additions & 0 deletions audio.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package vz

/*
#cgo darwin CFLAGS: -x objective-c -fno-objc-arc
#cgo darwin LDFLAGS: -lobjc -framework Foundation -framework Virtualization
# include "virtualization.h"
*/
import "C"
import "runtime"

// AudioDeviceConfiguration interface for an audio device configuration.
type AudioDeviceConfiguration interface {
NSObject

audioDeviceConfiguration()
}

type baseAudioDeviceConfiguration struct{}

func (*baseAudioDeviceConfiguration) audioDeviceConfiguration() {}

// VirtioSoundDeviceConfiguration is a struct that defines a Virtio sound device configuration.
//
// Use a VirtioSoundDeviceConfiguration to configure an audio device for your VM. After creating
// this struct, assign appropriate values via the SetStreams method which defines the behaviors of
// the underlying audio streams for this audio device.
//
// After creating and configuring a VirtioSoundDeviceConfiguration struct, assign it to the
// SetAudioDevicesVirtualMachineConfiguration method of your VM’s configuration.
type VirtioSoundDeviceConfiguration struct {
pointer

*baseAudioDeviceConfiguration
}

var _ AudioDeviceConfiguration = (*VirtioSoundDeviceConfiguration)(nil)

// NewVirtioSoundDeviceConfiguration creates a new sound device configuration.
func NewVirtioSoundDeviceConfiguration() *VirtioSoundDeviceConfiguration {
config := &VirtioSoundDeviceConfiguration{
pointer: pointer{
ptr: C.newVZVirtioSoundDeviceConfiguration(),
},
}
runtime.SetFinalizer(config, func(self *VirtioSoundDeviceConfiguration) {
self.Release()
})
return config
}

// SetStreams sets the list of audio streams exposed by this device.
func (v *VirtioSoundDeviceConfiguration) SetStreams(streams ...VirtioSoundDeviceStreamConfiguration) {
ptrs := make([]NSObject, len(streams))
for i, val := range streams {
ptrs[i] = val
}
array := convertToNSMutableArray(ptrs)
C.setStreamsVZVirtioSoundDeviceConfiguration(v.Ptr(), array.Ptr())
}

// VirtioSoundDeviceStreamConfiguration interface for Virtio Sound Device Stream Configuration.
type VirtioSoundDeviceStreamConfiguration interface {
NSObject

virtioSoundDeviceStreamConfiguration()
}

type baseVirtioSoundDeviceStreamConfiguration struct{}

func (*baseVirtioSoundDeviceStreamConfiguration) virtioSoundDeviceStreamConfiguration() {}

// VirtioSoundDeviceHostInputStreamConfiguration is a PCM stream of input audio data,
// such as from a microphone via host.
type VirtioSoundDeviceHostInputStreamConfiguration struct {
pointer

*baseVirtioSoundDeviceStreamConfiguration
}

var _ VirtioSoundDeviceStreamConfiguration = (*VirtioSoundDeviceHostInputStreamConfiguration)(nil)

// NewVirtioSoundDeviceHostInputStreamConfiguration creates a new PCM stream configuration of input audio data from host.
func NewVirtioSoundDeviceHostInputStreamConfiguration() *VirtioSoundDeviceHostInputStreamConfiguration {
config := &VirtioSoundDeviceHostInputStreamConfiguration{
pointer: pointer{
ptr: C.newVZVirtioSoundDeviceHostInputStreamConfiguration(),
},
}
runtime.SetFinalizer(config, func(self *VirtioSoundDeviceHostInputStreamConfiguration) {
self.Release()
})
return config
}

// VirtioSoundDeviceHostOutputStreamConfiguration is a struct that
// defines a Virtio host sound device output stream configuration.
//
// A PCM stream of output audio data, such as to a speaker from host.
type VirtioSoundDeviceHostOutputStreamConfiguration struct {
pointer

*baseVirtioSoundDeviceStreamConfiguration
}

var _ VirtioSoundDeviceStreamConfiguration = (*VirtioSoundDeviceHostOutputStreamConfiguration)(nil)

// NewVirtioSoundDeviceHostOutputStreamConfiguration creates a new sounds device output stream configuration.
func NewVirtioSoundDeviceHostOutputStreamConfiguration() *VirtioSoundDeviceHostOutputStreamConfiguration {
config := &VirtioSoundDeviceHostOutputStreamConfiguration{
pointer: pointer{
ptr: C.newVZVirtioSoundDeviceHostOutputStreamConfiguration(),
},
}
runtime.SetFinalizer(config, func(self *VirtioSoundDeviceHostOutputStreamConfiguration) {
self.Release()
})
return config
}
34 changes: 34 additions & 0 deletions bootloader_arm64.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//go:build darwin && arm64
// +build darwin,arm64

package vz

/*
#cgo darwin CFLAGS: -x objective-c -fno-objc-arc
#cgo darwin LDFLAGS: -lobjc -framework Foundation -framework Virtualization
# include "virtualization_arm64.h"
*/
import "C"
import "runtime"

// MacOSBootLoader is a boot loader configuration for booting macOS on Apple Silicon.
type MacOSBootLoader struct {
pointer

*baseBootLoader
}

var _ BootLoader = (*MacOSBootLoader)(nil)

// NewMacOSBootLoader creates a new MacOSBootLoader struct.
func NewMacOSBootLoader() *MacOSBootLoader {
bootLoader := &MacOSBootLoader{
pointer: pointer{
ptr: C.newVZMacOSBootLoader(),
},
}
runtime.SetFinalizer(bootLoader, func(self *MacOSBootLoader) {
self.Release()
})
return bootLoader
}
69 changes: 69 additions & 0 deletions configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,3 +145,72 @@ func (v *VirtualMachineConfiguration) SetDirectorySharingDevicesVirtualMachineCo
array := convertToNSMutableArray(ptrs)
C.setDirectorySharingDevicesVZVirtualMachineConfiguration(v.Ptr(), array.Ptr())
}

// SetPlatformVirtualMachineConfiguration sets the hardware platform to use. Defaults to GenericPlatformConfiguration.
func (v *VirtualMachineConfiguration) SetPlatformVirtualMachineConfiguration(c PlatformConfiguration) {
C.setPlatformVZVirtualMachineConfiguration(v.Ptr(), c.Ptr())
}

// SetGraphicsDevicesVirtualMachineConfiguration sets list of graphics devices. Empty by default.
func (v *VirtualMachineConfiguration) SetGraphicsDevicesVirtualMachineConfiguration(cs []GraphicsDeviceConfiguration) {
ptrs := make([]NSObject, len(cs))
for i, val := range cs {
ptrs[i] = val
}
array := convertToNSMutableArray(ptrs)
C.setGraphicsDevicesVZVirtualMachineConfiguration(v.Ptr(), array.Ptr())
}

// SetPointingDevicesVirtualMachineConfiguration sets list of pointing devices. Empty by default.
func (v *VirtualMachineConfiguration) SetPointingDevicesVirtualMachineConfiguration(cs []PointingDeviceConfiguration) {
ptrs := make([]NSObject, len(cs))
for i, val := range cs {
ptrs[i] = val
}
array := convertToNSMutableArray(ptrs)
C.setPointingDevicesVZVirtualMachineConfiguration(v.Ptr(), array.Ptr())
}

// SetKeyboardsVirtualMachineConfiguration sets list of keyboards. Empty by default.
func (v *VirtualMachineConfiguration) SetKeyboardsVirtualMachineConfiguration(cs []KeyboardConfiguration) {
ptrs := make([]NSObject, len(cs))
for i, val := range cs {
ptrs[i] = val
}
array := convertToNSMutableArray(ptrs)
C.setKeyboardsVZVirtualMachineConfiguration(v.Ptr(), array.Ptr())
}

// SetAudioDevicesVirtualMachineConfiguration sets list of audio devices. Empty by default.
func (v *VirtualMachineConfiguration) SetAudioDevicesVirtualMachineConfiguration(cs []AudioDeviceConfiguration) {
ptrs := make([]NSObject, len(cs))
for i, val := range cs {
ptrs[i] = val
}
array := convertToNSMutableArray(ptrs)
C.setAudioDevicesVZVirtualMachineConfiguration(v.Ptr(), array.Ptr())
}

// VirtualMachineConfigurationMinimumAllowedMemorySize returns minimum
// amount of memory required by virtual machines.
func VirtualMachineConfigurationMinimumAllowedMemorySize() uint64 {
return uint64(C.minimumAllowedMemorySizeVZVirtualMachineConfiguration())
}

// VirtualMachineConfigurationMaximumAllowedMemorySize returns maximum
// amount of memory allowed for a virtual machine.
func VirtualMachineConfigurationMaximumAllowedMemorySize() uint64 {
return uint64(C.maximumAllowedMemorySizeVZVirtualMachineConfiguration())
}

// VirtualMachineConfigurationMinimumAllowedCPUCount returns minimum
// number of CPUs for a virtual machine.
func VirtualMachineConfigurationMinimumAllowedCPUCount() uint {
return uint(C.minimumAllowedCPUCountVZVirtualMachineConfiguration())
}

// VirtualMachineConfigurationMaximumAllowedCPUCount returns maximum
// number of CPUs for a virtual machine.
func VirtualMachineConfigurationMaximumAllowedCPUCount() uint {
return uint(C.maximumAllowedCPUCountVZVirtualMachineConfiguration())
}
23 changes: 23 additions & 0 deletions disk.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package vz

import (
"os"
)

// CreateDiskImage is creating disk image with specified filename and filesize.
// For example, if you want to create disk with 64GiB, you can set "64 * 1024 * 1024 * 1024" to size.
//
// Note that if you have specified a pathname which already exists, this function
// returns os.ErrExist error. So you can handle it with os.IsExist function.
func CreateDiskImage(pathname string, size int64) error {
f, err := os.OpenFile(pathname, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
if err != nil {
return err
}
defer f.Close()

if err := f.Truncate(size); err != nil {
return err
}
return nil
}
File renamed without changes.
File renamed without changes.
4 changes: 2 additions & 2 deletions example/go.mod → example/linux/go.mod
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
module github.com/Code-Hex/vz/example
module github.com/Code-Hex/vz/example/linux

go 1.16

replace github.com/Code-Hex/vz/v2 => ../
replace github.com/Code-Hex/vz/v2 => ../../

require (
github.com/Code-Hex/vz/v2 v2.0.0-00010101000000-000000000000
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
10 changes: 10 additions & 0 deletions example/macOS/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.PHONY: all
all: build codesign

.PHONY: codesign
codesign:
codesign --entitlements vz.entitlements -s - ./virtualization

.PHONY: build
build:
go build -o virtualization .
19 changes: 19 additions & 0 deletions example/macOS/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Example
=======

You can get knowledge build and codesign process in Makefile.

## Build

```sh
make all
```

## Run

- `./virtualization -install` install macOS to your VM.
- `./virtualization` run macOS VM.

## Resources

Some resources will be created in `VM.bundle` directory on your home directory.
61 changes: 61 additions & 0 deletions example/macOS/bundle.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package main

import (
"fmt"
"os"
"path/filepath"
)

// CreateVMBundle creates macOS VM bundle path if not exists.
func CreateVMBundle() error {
return os.MkdirAll(GetVMBundlePath(), 0777)
}

// GetVMBundlePath gets macOS VM bundle path.
func GetVMBundlePath() string {
home, err := os.UserHomeDir()
if err != nil {
panic(err) //
}
return filepath.Join(home, "/VM.bundle/")
}

// GetAuxiliaryStoragePath gets a path for auxiliary storage.
func GetAuxiliaryStoragePath() string {
return filepath.Join(GetVMBundlePath(), "AuxiliaryStorage")
}

// GetDiskImagePath gets a path for disk image.
func GetDiskImagePath() string {
return filepath.Join(GetVMBundlePath(), "Disk.img")
}

// GetHardwareModelPath gets a path for hardware model.
func GetHardwareModelPath() string {
return filepath.Join(GetVMBundlePath(), "HardwareModel")
}

// GetMachineIdentifierPath gets a path for machine identifier.
func GetMachineIdentifierPath() string {
return filepath.Join(GetVMBundlePath(), "MachineIdentifier")
}

// GetRestoreImagePath gets a path for restore image file.
func GetRestoreImagePath() string {
return filepath.Join(GetVMBundlePath(), "RestoreImage.ipsw")
}

// CreateFileAndWriteTo creates a new file and write data to it.
func CreateFileAndWriteTo(data []byte, path string) error {
f, err := os.Create(path)
if err != nil {
return fmt.Errorf("failed to create file %q: %w", path, err)
}
defer f.Close()

_, err = f.Write(data)
if err != nil {
return fmt.Errorf("failed to write data: %w", err)
}
return nil
}
11 changes: 11 additions & 0 deletions example/macOS/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module github.com/Code-Hex/vz/example/macOS

go 1.16

replace github.com/Code-Hex/vz/v2 => ../../

require (
github.com/Code-Hex/vz/v2 v2.0.0-00010101000000-000000000000
github.com/pkg/term v1.1.0
golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664
)
7 changes: 7 additions & 0 deletions example/macOS/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
github.com/pkg/term v1.1.0 h1:xIAAdCMh3QIAy+5FrE8Ad8XoDhEU4ufwbaSozViP9kk=
github.com/pkg/term v1.1.0/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw=
github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY=
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664 h1:v1W7bwXHsnLLloWYTVEdvGvA7BHMeBYsPcF0GLDxIRs=
golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
Loading

0 comments on commit 8182bcf

Please sign in to comment.