├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── README.md ├── lib └── novm │ └── libexec │ ├── extract-vmlinux │ ├── init │ └── mkinitramfs ├── novm ├── __init__.py ├── basic.py ├── block.py ├── cli.py ├── clock.py ├── control.py ├── cpu.py ├── db.py ├── device.py ├── docker.py ├── exceptions.py ├── fs.py ├── ioctl.py ├── manager.py ├── memory.py ├── net.py ├── pci.py ├── prettyprint.py ├── serial.py ├── shell.py ├── state.py ├── utils.py └── virtio.py ├── packagers ├── DEBIAN │ └── control └── novm.spec ├── pkg-info ├── scripts ├── novm ├── novm-clear-kernels └── novm-import-kernel └── src ├── noguest ├── main.go ├── protocol │ ├── command.go │ ├── errors.go │ └── status.go └── rpc │ ├── read.go │ ├── server.go │ ├── start.go │ ├── wait.go │ └── write.go └── novmm ├── control ├── errors.go ├── guest.go ├── rpc_basic.go ├── rpc_device.go ├── rpc_state.go ├── rpc_trace.go ├── rpc_types.go ├── rpc_vcpu.go ├── server.go └── state.go ├── errors.go ├── loader ├── elf_load.c ├── elf_load.go ├── elf_load.h ├── errors.go ├── linux.go ├── linux_setup.go ├── linux_x86.go ├── sysmap.go └── trace.go ├── loop.go ├── machine ├── acpi.c ├── acpi.go ├── acpi.h ├── apic.go ├── bios.go ├── cache.go ├── clock.go ├── device.go ├── drivers.go ├── entry.go ├── errors.go ├── eventfd.go ├── interrupt.go ├── io.go ├── memory.go ├── mmio.go ├── model.go ├── msix.go ├── pci.go ├── pcihost.go ├── pio.go ├── pit.go ├── proxy.go ├── ram.go ├── register.go ├── rtc.go ├── state.go ├── uart.go ├── user.go ├── virtio.c ├── virtio.go ├── virtio.h ├── virtio_block.go ├── virtio_buffer.c ├── virtio_buffer.go ├── virtio_buffer.h ├── virtio_console.go ├── virtio_fs.go ├── virtio_net.go └── virtio_stream.go ├── main.go ├── plan9 ├── buffer.go ├── errors.go ├── fid.go ├── file.go ├── fmt.go ├── fs.go ├── ops.go ├── p9.go ├── pack.go ├── unpack.go └── xattr.go ├── platform ├── errors.go ├── eventfd_linux.go ├── exits.go ├── kvm.go ├── kvm_apic.go ├── kvm_caps.go ├── kvm_clock.go ├── kvm_cpuid.c ├── kvm_cpuid.go ├── kvm_cpuid.h ├── kvm_eventfd.go ├── kvm_events.go ├── kvm_exits.c ├── kvm_exits.go ├── kvm_exits.h ├── kvm_fpu.go ├── kvm_memory.go ├── kvm_mpstate.go ├── kvm_msrs.c ├── kvm_msrs.go ├── kvm_msrs.h ├── kvm_pit.go ├── kvm_run.c ├── kvm_run.go ├── kvm_run.h ├── kvm_vcpu.go ├── kvm_x86.go ├── kvm_xcrs.go ├── kvm_xsave.go ├── state.go ├── types.go ├── utils.go └── x86.go └── utils ├── decoder.go ├── die.go ├── encoder.go └── signals.go /.gitignore: -------------------------------------------------------------------------------- 1 | gorc 2 | bin 3 | dist 4 | pkg 5 | _obj 6 | debbuild/ 7 | rpmbuild/ 8 | *.deb 9 | *.rpm 10 | *.pyc 11 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Want to contribute? Great! First, read this page (including the small print at 2 | the end). 3 | 4 | ### Before you contribute 5 | 6 | Before we can use your code, you must sign the [Google Individual Contributor 7 | License 8 | Agreement](https://developers.google.com/open-source/cla/individual?csw=1) 9 | (CLA), which you can do online. The CLA is necessary mainly because you own the 10 | copyright to your changes, even after your contribution becomes part of our 11 | codebase, so we need your permission to use and distribute your code. We also 12 | need to be sure of various other things—for instance that you'll tell us if you 13 | know that your code infringes on other people's patents. You don't have to sign 14 | the CLA until after you've submitted your code for review and a member has 15 | approved it, but you must do it before we can put your code into our codebase. 16 | Before you start working on a larger contribution, you should get in touch with 17 | us first through the issue tracker with your idea so that we can help out and 18 | possibly guide you. Coordinating up front makes it much easier to avoid 19 | frustration later on. 20 | 21 | ### Code reviews 22 | All submissions, including submissions by project members, require review. We 23 | use Github pull requests for this purpose. 24 | 25 | ### The small print 26 | Contributions made by corporations are covered by a different agreement than 27 | the one above, the Software Grant and Corporate Contributor License Agreement. 28 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | # Common package information. 4 | include pkg-info 5 | 6 | DESCRIPTION := $(shell git describe --tags --match 'v*' | cut -d'v' -f2-) 7 | VERSION ?= $(shell echo $(DESCRIPTION) | cut -d'-' -f1) 8 | RELEASE ?= $(shell echo $(DESCRIPTION) | cut -d'-' -f2- -s | tr '-' '.') 9 | ARCH ?= $(shell go env GOARCH) 10 | 11 | ifeq ($(VERSION),) 12 | $(error No VERSION available, please set manually.) 13 | endif 14 | ifeq ($(RELEASE),) 15 | RELEASE := 1 16 | endif 17 | 18 | ifeq ($(ARCH),amd64) 19 | DEB_ARCH := amd64 20 | RPM_ARCH := x86_64 21 | KERNEL_ARCH := x86 22 | else 23 | ifeq ($(ARCH),386) 24 | DEB_ARCH := i386 25 | RPM_ARCH := i386 26 | KERNEL_ARCH := x86 27 | else 28 | $(error Unknown arch "$(ARCH)".) 29 | endif 30 | endif 31 | 32 | ifeq ($(KERNEL),y) 33 | # Figure out our kernel path. 34 | # You can override all these settings, but 35 | # nothing will be added unless you pass KERNEL=y. 36 | KERNEL_RELEASE ?= $(shell uname -r) 37 | KERNEL_SOURCE ?= /lib/modules/$(KERNEL_RELEASE)/build 38 | KERNEL_INCLUDE ?= $(KERNEL_SOURCE)/include/uapi 39 | KERNEL_ARCH_INCLUDE ?= $(KERNEL_SOURCE)/arch/$(KERNEL_ARCH)/include/uapi 40 | CGO_CFLAGS ?= -I$(KERNEL_INCLUDE) -I$(KERNEL_ARCH_INCLUDE) 41 | endif 42 | 43 | # Our default target. 44 | all: dist 45 | .PHONY: all 46 | 47 | # Our GO source build command. 48 | # This includes our kernel include path (if set). 49 | go_build = @GOPATH=$(CURDIR) CGO_CFLAGS="$(CGO_CFLAGS)" $(1) 50 | 51 | ARCH ?= $(shell arch) 52 | go-build: go-fmt go-test 53 | go-install: go-fmt go-test 54 | go-%: 55 | $(call go_build,go $* novmm) 56 | $(call go_build,go $* noguest) 57 | go-bench: 58 | $(call go_build,go test -bench=".*" novmm) 59 | $(call go_build,go test -bench=".*" noguest) 60 | go-fmt: 61 | $(call go_build,gofmt -l=true -w=true src/novmm/$*) 62 | $(call go_build,gofmt -l=true -w=true src/noguest/$*) 63 | 64 | test: go-test 65 | .PHONY: test 66 | 67 | fmt: go-fmt 68 | .PHONY: fmt 69 | 70 | clean: 71 | @rm -rf bin/ pkg/ dist/ doc/ _obj 72 | @rm -rf debbuild/ rpmbuild/ *.deb *.rpm 73 | .PHONY: clean 74 | 75 | dist: 76 | @# Build the tools. 77 | @$(MAKE) clean && $(MAKE) go-install 78 | @# Install our scripts. 79 | @mkdir -p dist/usr/bin 80 | @install -m 0755 scripts/* dist/usr/bin 81 | @# Install our libexec directory. 82 | @rm -rf dist/lib && cp -ar lib/ dist/usr/lib 83 | @install -m 0755 bin/* dist/usr/lib/novm/libexec 84 | @# Install our python code. 85 | @mkdir -p dist/usr/lib/novm/python 86 | @rsync -ru --delete --exclude=*.pyc novm \ 87 | dist/usr/lib/novm/python/ 88 | 89 | .PHONY: dist 90 | 91 | deb: dist 92 | @rm -rf debbuild && mkdir -p debbuild 93 | @rsync -ruav packagers/DEBIAN debbuild 94 | @rsync -ruav dist/ debbuild 95 | @chmod 755 debbuild/DEBIAN 96 | @sed -i "s/VERSION/$(VERSION)-$(RELEASE)/" debbuild/DEBIAN/control 97 | @sed -i "s/MAINTAINER/$(MAINTAINER)/" debbuild/DEBIAN/control 98 | @sed -i "s/ARCHITECTURE/$(DEB_ARCH)/" debbuild/DEBIAN/control 99 | @sed -i "s/SUMMARY/$(SUMMARY)/" debbuild/DEBIAN/control 100 | @sed -i "s#URL#$(URL)#" debbuild/DEBIAN/control 101 | @fakeroot dpkg -b debbuild/ . 102 | .PHONY: deb 103 | 104 | rpm: dist 105 | @rm -rf rpmbuild && mkdir -p rpmbuild 106 | @rpmbuild -bb --buildroot $(PWD)/rpmbuild/BUILDROOT \ 107 | --define="%_topdir $(PWD)/rpmbuild" \ 108 | --define="%version $(VERSION)" \ 109 | --define="%release $(RELEASE)" \ 110 | --define="%maintainer $(MAINTAINER)" \ 111 | --define="%architecture $(RPM_ARCH)" \ 112 | --define="%summary $(SUMMARY)" \ 113 | --define="%url $(URL)" \ 114 | packagers/novm.spec 115 | @mv rpmbuild/RPMS/$(RPM_ARCH)/*.rpm . 116 | .PHONY: rpm 117 | 118 | packages: deb rpm 119 | .PHONY: packages 120 | -------------------------------------------------------------------------------- /lib/novm/libexec/extract-vmlinux: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------- 3 | # extract-vmlinux - Extract uncompressed vmlinux from a kernel image 4 | # 5 | # Inspired from extract-ikconfig 6 | # (c) 2009,2010 Dick Streefland 7 | # 8 | # (c) 2011 Corentin Chary 9 | # 10 | # Licensed under the GNU General Public License, version 2 (GPLv2). 11 | # ---------------------------------------------------------------------- 12 | 13 | check_vmlinux() 14 | { 15 | # Use readelf to check if it's a valid ELF 16 | # TODO: find a better to way to check that it's really vmlinux 17 | # and not just an elf 18 | readelf -h $1 > /dev/null 2>&1 || return 1 19 | 20 | cat $1 21 | exit 0 22 | } 23 | 24 | try_decompress() 25 | { 26 | # The obscure use of the "tr" filter is to work around older versions of 27 | # "grep" that report the byte offset of the line instead of the pattern. 28 | 29 | # Try to find the header ($1) and decompress from here 30 | for pos in `tr "$1\n$2" "\n$2=" < "$img" | grep -abo "^$2"` 31 | do 32 | pos=${pos%%:*} 33 | tail -c+$pos "$img" | $3 > $tmp 2> /dev/null 34 | check_vmlinux $tmp 35 | done 36 | } 37 | 38 | # Check invocation: 39 | me=${0##*/} 40 | img=$1 41 | if [ $# -ne 1 -o ! -s "$img" ] 42 | then 43 | echo "Usage: $me " >&2 44 | exit 2 45 | fi 46 | 47 | # Prepare temp files: 48 | tmp=$(mktemp /tmp/vmlinux-XXX) 49 | trap "rm -f $tmp" 0 50 | 51 | # Initial attempt for uncompressed images or objects: 52 | check_vmlinux $img 53 | 54 | # That didn't work, so retry after decompression. 55 | try_decompress '\037\213\010' xy gunzip 56 | try_decompress '\3757zXZ\000' abcde unxz 57 | try_decompress 'BZh' xy bunzip2 58 | try_decompress '\135\0\0\0' xxx unlzma 59 | try_decompress '\211\114\132' xy 'lzop -d' 60 | 61 | # Bail out: 62 | echo "$me: Cannot find vmlinux." >&2 63 | -------------------------------------------------------------------------------- /lib/novm/libexec/init: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright 2014 Google Inc. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # Small victory. 18 | echo "~~~ NOVM ~~~" >/dev/kmsg 19 | 20 | # Mount proc, etc. 21 | mount -t proc proc /proc 22 | mount -t sysfs sysfs /sys 23 | mount -t tmpfs tmpfs /run 24 | mount -t devtmpfs devtmpfs /dev 25 | mount -t devpts devpts /dev/pts 26 | 27 | # Load all virt-io modules. 28 | modprobe virtio 29 | modprobe virtio-ring 30 | modprobe virtio-pci 31 | modprobe virtio-net 32 | modprobe virtio-blk 33 | modprobe virtio-console 34 | modprobe 9pnet_virtio 35 | modprobe 9p 36 | 37 | # Mount our root context. 38 | mkdir -p /sysroot 39 | mount -t 9p -o trans=virtio,version=9p2000.u,cache=fscache,access=any,rw root /sysroot 40 | 41 | # Mount our init context. 42 | # We stash the init binary inside file descriptor 3. 43 | # This allows us to cleanly unmount everything here, 44 | # while still executing this process once we're in the 45 | # real root filesystem. 46 | mkdir -p /sysinit 47 | mount -t 9p -o trans=virtio,version=9p2000.u,cache=fscache,access=any,ro init /sysinit 48 | exec 3/dev/kmsg 2>&1 57 | -------------------------------------------------------------------------------- /novm/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014 Google Inc. All rights reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | """ novm """ 15 | -------------------------------------------------------------------------------- /novm/basic.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014 Google Inc. All rights reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | """ 15 | Basic devices. 16 | """ 17 | from . import device 18 | 19 | class Bios(device.Driver): 20 | 21 | driver = "bios" 22 | 23 | class Acpi(device.Driver): 24 | 25 | driver = "acpi" 26 | 27 | def create(self, **kwargs): 28 | # Our ACPI implementation is currently 29 | # quite broken (we don't even have a DSDT). 30 | # Therefore, to stop Linux from complaining, 31 | # we intentionally disable power-states. 32 | return super(Acpi, self).create( 33 | cmdline="intel_pstate=disable", 34 | **kwargs) 35 | 36 | class Apic(device.Driver): 37 | 38 | driver = "apic" 39 | 40 | class Pit(device.Driver): 41 | 42 | driver = "pit" 43 | 44 | device.Driver.register(Bios) 45 | device.Driver.register(Acpi) 46 | device.Driver.register(Apic) 47 | device.Driver.register(Pit) 48 | -------------------------------------------------------------------------------- /novm/block.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014 Google Inc. All rights reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | """ 15 | Block device functions. 16 | """ 17 | import os 18 | 19 | from . import virtio 20 | from . import utils 21 | 22 | class Disk(virtio.Driver): 23 | 24 | """ A Virtio block device. """ 25 | 26 | virtio_driver = "block" 27 | 28 | def create(self, 29 | index=0, 30 | filename=None, 31 | dev=None, 32 | **kwargs): 33 | 34 | if filename is None: 35 | filename = "/dev/null" 36 | if dev is None: 37 | dev = "vd" + chr(ord("a") + index) 38 | 39 | # Open the device. 40 | f = open(filename, 'r+b') 41 | fd = os.dup(f.fileno()) 42 | utils.clear_cloexec(fd) 43 | 44 | return super(Disk, self).create(data={ 45 | "dev": dev, 46 | "fd": fd, 47 | }, **kwargs) 48 | 49 | virtio.Driver.register(Disk) 50 | -------------------------------------------------------------------------------- /novm/clock.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014 Google Inc. All rights reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | """ 15 | Timers, etc. 16 | """ 17 | from . import device 18 | 19 | class Rtc(device.Driver): 20 | 21 | driver = "rtc" 22 | 23 | device.Driver.register(Rtc) 24 | -------------------------------------------------------------------------------- /novm/cpu.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014 Google Inc. All rights reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | """ 15 | Basic CPU state. 16 | """ 17 | from . import state 18 | 19 | class Cpu(state.State): 20 | 21 | """ Basic CPU state. """ 22 | 23 | # A CPU can be modeled directly using its state, 24 | # without any external links (like files or network 25 | # tap devices, for example). Therefore, it is much 26 | # simpler than the device model. 27 | -------------------------------------------------------------------------------- /novm/device.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014 Google Inc. All rights reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | """ 15 | Device specification. 16 | """ 17 | import uuid 18 | 19 | from . import state 20 | from . import utils 21 | 22 | class Device(state.State): 23 | 24 | """ Basic device state. """ 25 | 26 | def cmdline(self): 27 | """ Return a Linux cmdline parameter. """ 28 | return self.get("cmdline") 29 | 30 | class Driver(object): 31 | 32 | # The global set of all our device 33 | # classes. When we save / resume novm 34 | # state, we will look up drivers here 35 | # in order to run the appropriate fns. 36 | REGISTRY = {} 37 | 38 | @staticmethod 39 | def register(cls, driver=None): 40 | if driver is None: 41 | driver = cls.driver 42 | Driver.REGISTRY[driver] = cls 43 | 44 | @staticmethod 45 | def lookup(driver): 46 | return Driver.REGISTRY[driver] 47 | 48 | @property 49 | def name(self): 50 | """ Return a simple identifier for this device. """ 51 | return str(uuid.uuid4()) 52 | 53 | @property 54 | def debug(self): 55 | """ Return whether this device is debugging. """ 56 | return False 57 | 58 | @property 59 | def driver(self): 60 | """ Return the driver for novmm. """ 61 | raise NotImplementedError() 62 | 63 | def create(self, 64 | driver=None, 65 | name=None, 66 | data=None, 67 | debug=False, 68 | cmdline=None): 69 | 70 | """ Create a new device. """ 71 | return Device( 72 | driver=driver or self.driver, 73 | name=name or self.name, 74 | data=data or {}, 75 | debug=utils.asbool(debug) or self.debug, 76 | cmdline=cmdline or None) 77 | -------------------------------------------------------------------------------- /novm/exceptions.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014 Google Inc. All rights reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | """ 15 | Exceptions. 16 | """ 17 | 18 | class CommandInvalid(Exception): 19 | 20 | def __init__(self): 21 | super(CommandInvalid, self).__init__("Invalid command") 22 | -------------------------------------------------------------------------------- /novm/fs.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014 Google Inc. All rights reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | """ 15 | Filesystem device functions. 16 | """ 17 | import os 18 | import uuid 19 | import tempfile 20 | import shutil 21 | 22 | from . import utils 23 | from . import virtio 24 | 25 | class FS(virtio.Driver): 26 | 27 | """ Virtio Filesystem (plan9) """ 28 | 29 | virtio_driver = "fs" 30 | 31 | def create(self, 32 | tag=None, 33 | tempdir=None, 34 | read=None, 35 | write=None, 36 | fdlimit=None, 37 | **kwargs): 38 | 39 | if tag is None: 40 | tag = str(uuid.uuid4()) 41 | if read is None: 42 | read = [] 43 | if write is None: 44 | write = [] 45 | if tempdir is None: 46 | tempdir = tempfile.mkdtemp() 47 | utils.cleanup(shutil.rmtree, tempdir) 48 | if not os.path.exists(tempdir): 49 | os.makedirs(tempdir) 50 | 51 | # Append our read mapping. 52 | read_map = {'/': []} 53 | for path in read: 54 | spec = path.split("=>", 1) 55 | if len(spec) == 1: 56 | read_map['/'].append(path) 57 | else: 58 | if not spec[0] in read_map: 59 | read_map[spec[0]] = [] 60 | read_map[spec[0]].append(spec[1]) 61 | 62 | # Append our write mapping. 63 | write_map = {'/': tempdir} 64 | 65 | for path in write: 66 | spec = path.split("=>", 1) 67 | if len(spec) == 1: 68 | write_map['/'] = path 69 | else: 70 | write_map[spec[0]] = spec[1] 71 | 72 | # Create our device. 73 | return super(FS, self).create(data={ 74 | "read": read_map, 75 | "write": write_map, 76 | "tag": tag, 77 | "fdlimit": fdlimit or 0, 78 | }, **kwargs) 79 | 80 | virtio.Driver.register(FS) 81 | -------------------------------------------------------------------------------- /novm/ioctl.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014 Google Inc. All rights reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | """ 15 | Python adaptation of . 16 | """ 17 | import platform 18 | 19 | # Ioctl numbers are encoded in 32 bits: 20 | # 1 - 16: command 21 | # 17 - 30: param struct size 22 | # 31 - 32: direction 23 | # 24 | # Technically these offsets are architecture dependant, but in practice they don't 25 | # change. In particular, on x86_32 and x86_64, they're the same. 26 | 27 | # Argument sizes. Assumes python is same arch as kernel. That is, you can't make 28 | # an ioctl from a 32-bit python process into a 64-bit kernel. Technically, 29 | # there's nothing stopping you from doing so, but your structure sizes will be 30 | # all messed up. We use platform.machine(), which is AMD64 or x86_64 on 64-bit, 31 | # to identify kernel bit-ness. 32 | # 33 | # In addition to determining argument sizes, we also provide the correct format 34 | # string to use for (unsigned) long in struct format strings. Unfortunately, in 35 | # the struct module, sizes cannot be both native and unpadded. If you use an 36 | # unpadded format specifier ('='), as you should in an ABI, then you always get 37 | # the "standard" (unsigned) long size of 4, which makes no sense on a 64-bit 38 | # kernel. To use use a 64-bit kernel's long size in a packed struct, you have to 39 | # use the "standard" long long format. So (UNSIGNED_)LONG_PACKED_FMT is 40 | # exported with the correct format. 41 | if '64' in platform.machine(): 42 | POINTER_SIZE = 8 43 | LONG_PACKED_FMT = 'q' 44 | else: 45 | POINTER_SIZE = 4 46 | LONG_PACKED_FMT = 'l' 47 | UNSIGNED_LONG_PACKED_FMT = LONG_PACKED_FMT.upper() 48 | LONG_SIZE = UNSIGNED_LONG_SIZE = POINTER_SIZE 49 | UNSIGNED_LONG_LONG_SIZE = 8 50 | 51 | # Number of bits per field. 52 | _IOC_NRBITS = 8 53 | _IOC_TYPEBITS = 8 54 | _IOC_SIZEBITS = 14 55 | _IOC_DIRBITS = 2 56 | 57 | # Shifts for each field. 58 | _IOC_NRSHIFT = 0 59 | _IOC_TYPESHIFT = _IOC_NRSHIFT + _IOC_NRBITS 60 | _IOC_SIZESHIFT = _IOC_TYPESHIFT + _IOC_TYPEBITS 61 | _IOC_DIRSHIFT = _IOC_SIZESHIFT + _IOC_SIZEBITS 62 | 63 | # Direction bits. 64 | _IOC_NONE = 0 65 | _IOC_WRITE = 1 66 | _IOC_READ = 2 67 | 68 | def _IOC(dir, type, nr, size): 69 | '''Encodes dir, type, nr, and size into 32-bit ioctl number.''' 70 | return (dir << _IOC_DIRSHIFT) | \ 71 | (type << _IOC_TYPESHIFT) | \ 72 | (nr << _IOC_NRSHIFT) | \ 73 | (size << _IOC_SIZESHIFT) 74 | 75 | _IOWR = lambda type, nr, size: _IOC(_IOC_READ | _IOC_WRITE, type, nr, size) 76 | _IOW = lambda type, nr, size: _IOC(_IOC_WRITE, type, nr, size) 77 | _IOR = lambda type, nr, size: _IOC(_IOC_READ, type, nr, size) 78 | _IO = lambda type, nr: _IOC(_IOC_NONE, type, nr, 0) 79 | -------------------------------------------------------------------------------- /novm/memory.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014 Google Inc. All rights reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | """ 15 | Memory devices. 16 | """ 17 | import os 18 | import tempfile 19 | 20 | from . import device 21 | from . import utils 22 | 23 | class UserMemory(device.Driver): 24 | 25 | driver = "user-memory" 26 | 27 | def create(self, 28 | size=None, 29 | fd=None, 30 | **kwargs): 31 | 32 | # No file given? 33 | if fd is None: 34 | with tempfile.NamedTemporaryFile() as tf: 35 | fd = os.dup(tf.fileno()) 36 | utils.clear_cloexec(fd) 37 | 38 | # No size given? Default to file size. 39 | if size is None: 40 | fd_stat = os.fstat(fd) 41 | size = fd_stat.st_size 42 | 43 | # Truncate the file. 44 | os.ftruncate(fd, size) 45 | 46 | return super(UserMemory, self).create(data={ 47 | "fd": fd, 48 | "size": size, 49 | }, **kwargs) 50 | 51 | def save(self, state, pid): 52 | """ Open up the fd and return it back. """ 53 | return ({ 54 | # Save the size of the memory block. 55 | "size": state.get("size"), 56 | }, { 57 | # Serialize the entire open fd. 58 | "memory": open("/proc/%d/fd/%d" % (pid, state["fd"]), "r") 59 | }) 60 | 61 | def load(self, state, files): 62 | return self.create( 63 | size=state.get("size"), 64 | fd=files["memory"].fileno()) 65 | 66 | device.Driver.register(UserMemory) 67 | -------------------------------------------------------------------------------- /novm/pci.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014 Google Inc. All rights reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | """ 15 | PCI functionality. 16 | """ 17 | from . import device 18 | 19 | class PciBus(device.Driver): 20 | 21 | driver = "pci-bus" 22 | 23 | def create(self, **kwargs): 24 | return super(PciBus, self).create( 25 | cmdline="pci=conf1", 26 | **kwargs) 27 | 28 | class PciHostBridge(device.Driver): 29 | 30 | # NOTE: For now, PCI support is pretty sketchy. 31 | # Generally, we'll need to have a hostbridge appear 32 | # in the list of devices. 33 | # For information on the bridge that might normally 34 | # appear, see src/novmm/machine/pcihost.go. 35 | 36 | driver = "pci-hostbridge" 37 | 38 | device.Driver.register(PciBus) 39 | device.Driver.register(PciHostBridge) 40 | -------------------------------------------------------------------------------- /novm/prettyprint.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014 Google Inc. All rights reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | """ 15 | Pretty-printing. 16 | """ 17 | import time 18 | import types 19 | 20 | def prettyprint(value, output): 21 | 22 | if isinstance(value, type(None)): 23 | # Print nothing. 24 | pass 25 | 26 | elif (isinstance(value, list) or 27 | isinstance(value, dict)): 28 | 29 | if len(value) == 0: 30 | # Empty list? 31 | return 32 | 33 | # Standardize lists and dictionaries. 34 | if isinstance(value, list): 35 | keys = list(range(len(value))) 36 | values = value 37 | else: 38 | def try_int(k): 39 | try: 40 | return int(k) 41 | except ValueError: 42 | return k 43 | 44 | items = sorted([(try_int(k), v) for (k, v) in list(value.items())]) 45 | keys = [x[0] for x in items] 46 | values = [x[1] for x in items] 47 | 48 | # Get the first instance. 49 | # Standardize as a dictionary. 50 | proto = values[0] 51 | if not isinstance(proto, dict): 52 | values = [{"value": x} for x in values] 53 | 54 | # Set a special element "id", 55 | # which in the case of a dictionary will 56 | # be the index into the list. In the case 57 | # of a dictionary, it'll be the key. 58 | # NOTE: We ensure below that the key "id" 59 | # is the first element in the sorted keys. 60 | for k, v in zip(keys, values): 61 | v["id"] = k 62 | 63 | def format_entry(k, v): 64 | if isinstance(v, float) and k == "timestamp": 65 | # Hack to print the time. 66 | return time.ctime(v) 67 | elif isinstance(v, list): 68 | return ",".join([str(x) for x in v]) 69 | elif v is not None: 70 | return str(v) 71 | else: 72 | return "" 73 | 74 | # Compute column widths. 75 | max_width = {} 76 | for entry in values: 77 | for k, v in list(entry.items()): 78 | max_width[k] = max( 79 | max_width.get(k, 0), 80 | len(format_entry(k, v)), 81 | len(k)) 82 | 83 | all_keys = list(max_width.keys()) 84 | all_keys.remove("id") 85 | all_keys.insert(0, "id") 86 | 87 | def fmt_row(entry): 88 | cols = " | ".join([ 89 | ("%%-%ds" % max_width[k]) % format_entry(k, entry.get(k)) 90 | for k in all_keys]) 91 | return "".join(["| ", cols, " |" ]) 92 | 93 | def sep_row(): 94 | return "-" * (4+sum(max_width.values())+3*(len(max_width)-1)) 95 | 96 | # Dump our output. 97 | output.write(sep_row() + "\n") 98 | output.write(fmt_row(dict([(k, k) for k in list(max_width.keys())])) + "\n") 99 | output.write(sep_row() + "\n") 100 | for entry in values: 101 | output.write(fmt_row(entry) + "\n") 102 | output.write(sep_row() + "\n") 103 | 104 | else: 105 | # Default object. 106 | output.write(str(value) + "\n") 107 | return 108 | 109 | def plainprint(value, output): 110 | 111 | if isinstance(value, type(None)): 112 | # Print nothing. 113 | pass 114 | 115 | elif (isinstance(value, list) or 116 | isinstance(value, dict)): 117 | # Print individual values. 118 | for subvalue in value: 119 | output.write("%s\n" % subvalue) 120 | 121 | else: 122 | # Print the single value. 123 | output.write("%s\n" % value) 124 | -------------------------------------------------------------------------------- /novm/serial.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014 Google Inc. All rights reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | """ 15 | Console functions. 16 | """ 17 | from . import device 18 | from . import virtio 19 | 20 | class Console(virtio.Driver): 21 | 22 | """ A Virtio serial/console device. """ 23 | 24 | virtio_driver = "console" 25 | 26 | class Uart(device.Driver): 27 | 28 | driver = "uart" 29 | 30 | def com1(self, **kwargs): 31 | return self.create(data={ 32 | "base": 0x3f8, 33 | "interrupt": 4, 34 | }, 35 | cmdline="console=uart,io,0x3f8", 36 | **kwargs) 37 | 38 | def com2(self, **kwargs): 39 | return self.create(data={ 40 | "base": 0x2f8, 41 | "interrupt": 3, 42 | }, 43 | cmdline="console=uart,io,0x2f8", 44 | **kwargs) 45 | 46 | virtio.Driver.register(Console) 47 | device.Driver.register(Uart) 48 | -------------------------------------------------------------------------------- /novm/state.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014 Google Inc. All rights reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | """ 15 | Serializable state. 16 | 17 | This is a class which accepts arbitrary 18 | arguments and implements a basic interface 19 | to get/set state and retreive it. It is 20 | essentially a dictionary. 21 | """ 22 | 23 | class State(object): 24 | 25 | def __init__(self, **kwargs): 26 | self._state = kwargs 27 | 28 | def state(self): 29 | """ Returns the full state. """ 30 | return self._state 31 | 32 | def get(self, key, default=None): 33 | """ Return a single data item. """ 34 | return self._state.get(key, default) 35 | -------------------------------------------------------------------------------- /novm/virtio.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014 Google Inc. All rights reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | """ 15 | Virtio device specification. 16 | """ 17 | 18 | from . import device 19 | 20 | class Driver(device.Driver): 21 | 22 | @staticmethod 23 | def register(cls): 24 | device.Driver.register(cls, driver="virtio-pci-%s" % cls.virtio_driver) 25 | device.Driver.register(cls, driver="virtio-mmio-%s" % cls.virtio_driver) 26 | 27 | @property 28 | def virtio_driver(self): 29 | raise NotImplementedError() 30 | 31 | def create(self, 32 | index=-1, 33 | pci=False, 34 | data=None, 35 | **kwargs): 36 | 37 | if data is None: 38 | data = {} 39 | 40 | if pci: 41 | driver = "virtio-pci-%s" % self.virtio_driver 42 | else: 43 | driver = "virtio-mmio-%s" % self.virtio_driver 44 | 45 | if index >= 0 and not pci: 46 | # Are we an MMIO device? 47 | # NOTE: We arbitrarily pick 0xeXXXXXXX as the 48 | # start for all of our virtio devices. If we 49 | # have to do anymore reservation for I/O devices, 50 | # we might want to consider implemented something 51 | # a bit more thorough here. 52 | data["address"] = 0xe0000000 + index*4096 53 | data["interrupt"] = 32 + index 54 | cmdline = "virtio-mmio.%d@0x%x:%d:%d" % ( 55 | index, 56 | 0xe0000000 + index*4096, 57 | 32 + index, 58 | index) 59 | else: 60 | cmdline = None 61 | 62 | return super(Driver, self).create( 63 | data=data, 64 | driver=driver, 65 | cmdline=cmdline, 66 | **kwargs) 67 | -------------------------------------------------------------------------------- /packagers/DEBIAN/control: -------------------------------------------------------------------------------- 1 | Package: novm 2 | Section: extra 3 | Version: VERSION 4 | Architecture: ARCHITECTURE 5 | Maintainer: MAINTAINER 6 | Description: SUMMARY 7 | Homepage: URL 8 | Depends: dnsmasq, bridge-utils, fakeroot 9 | -------------------------------------------------------------------------------- /packagers/novm.spec: -------------------------------------------------------------------------------- 1 | Name: novm 2 | Summary: %{summary} 3 | Version: %{version} 4 | Release: %{release} 5 | Group: System 6 | License: ASL 2.0 7 | URL: %{url} 8 | Packager: %{maintainer} 9 | BuildArch: %{architecture} 10 | BuildRoot: %{_tmppath}/%{name}.%{version}-buildroot 11 | Requires: dnsmasq, bridge-utils, fakeroot 12 | 13 | # To prevent ypm/rpm/zypper/etc from complaining about FileDigests when 14 | # installing we set the algorithm explicitly to MD5SUM. This should be 15 | # compatible across systems (e.g. RedHat or openSUSE) and is backwards 16 | # compatible. 17 | %global _binary_filedigest_algorithm 1 18 | 19 | %description 20 | %{summary} 21 | 22 | %install 23 | rm -rf $RPM_BUILD_ROOT 24 | install -d $RPM_BUILD_ROOT 25 | rsync -rav --delete ../../dist/* $RPM_BUILD_ROOT 26 | 27 | %files 28 | /usr/bin/novm 29 | /usr/bin/novm-import-kernel 30 | /usr/bin/novm-clear-kernels 31 | /usr/lib/novm 32 | 33 | %changelog 34 | * Sat Dec 07 2013 Adin Scannell 35 | - Initial package creation. 36 | -------------------------------------------------------------------------------- /pkg-info: -------------------------------------------------------------------------------- 1 | # Basic package information. 2 | MAINTAINER ?= Adin Scannell 3 | SUMMARY ?= A high-performance, next-generation hypervisor written in Go. 4 | URL ?= https://github.com/google/novm 5 | -------------------------------------------------------------------------------- /scripts/novm: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright 2014 Google Inc. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | """ 18 | novm management script. 19 | """ 20 | 21 | import os 22 | import sys 23 | 24 | if os.path.exists(os.path.join("novm", "__init__.py")): 25 | sys.path.insert(0, ".") 26 | 27 | lib_path = os.path.join( 28 | os.path.abspath(os.path.dirname(__file__)), 29 | "..", "lib", "novm", "python") 30 | sys.path.append(lib_path) 31 | 32 | import novm.cli 33 | 34 | if __name__ == "__main__": 35 | novm.cli.main(sys.argv[1:]) 36 | -------------------------------------------------------------------------------- /scripts/novm-clear-kernels: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2014 Google Inc. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -e 18 | 19 | DIRNAME=$(dirname $0) 20 | for kernel in $($DIRNAME/novm --plain kernels); do 21 | $DIRNAME/novm rmkernel --id $kernel 22 | done 23 | -------------------------------------------------------------------------------- /scripts/novm-import-kernel: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2014 Google Inc. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -e 18 | 19 | if [ "$#" -gt "0" ]; then 20 | RELEASE=$1 21 | shift 22 | else 23 | RELEASE=$(uname -r) 24 | fi 25 | 26 | DIRNAME=$(dirname $0) 27 | URL=$(PATH=$PATH:/sbin:/usr/sbin fakeroot $DIRNAME/novm mkkernel --release=$RELEASE "$@") 28 | $DIRNAME/novm getkernel --url $URL 29 | -------------------------------------------------------------------------------- /src/noguest/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "flag" 19 | "log" 20 | "noguest/protocol" 21 | "noguest/rpc" 22 | "os" 23 | "os/exec" 24 | "syscall" 25 | ) 26 | 27 | // The default control file. 28 | var control = flag.String("control", "/dev/vport0p0", "control file") 29 | 30 | // Should this always run a server. 31 | var server_fd = flag.Int("serverfd", -1, "run RPC server") 32 | 33 | func mount(fs string, location string) error { 34 | 35 | // Do we have the location? 36 | _, err := os.Stat(location) 37 | if err != nil { 38 | // Make sure it's a directory. 39 | err = os.Mkdir(location, 0755) 40 | if err != nil { 41 | return err 42 | } 43 | } 44 | 45 | // Try to mount it. 46 | cmd := exec.Command("/bin/mount", "-t", fs, fs, location) 47 | return cmd.Run() 48 | } 49 | 50 | func main() { 51 | var console *os.File 52 | 53 | // Parse flags. 54 | flag.Parse() 55 | 56 | if *server_fd == -1 { 57 | // Open the console. 58 | if f, err := os.OpenFile(*control, os.O_RDWR, 0); err != nil { 59 | log.Fatal("Problem opening console:", err) 60 | } else { 61 | console = f 62 | } 63 | 64 | // Make sure devpts is mounted. 65 | err := mount("devpts", "/dev/pts") 66 | if err != nil { 67 | log.Fatal(err) 68 | } 69 | 70 | // Notify novmm that we're ready. 71 | buffer := make([]byte, 1, 1) 72 | buffer[0] = protocol.NoGuestStatusOkay 73 | n, err := console.Write(buffer) 74 | if err != nil || n != 1 { 75 | log.Fatal(err) 76 | } 77 | 78 | // Read our response. 79 | n, err = console.Read(buffer) 80 | if n != 1 || err != nil { 81 | log.Fatal(protocol.UnknownCommand) 82 | } 83 | 84 | // Rerun to cleanup argv[0], or create a real init. 85 | new_args := make([]string, 0, len(os.Args)+1) 86 | new_args = append(new_args, "noguest") 87 | new_args = append(new_args, "-serverfd", "0") 88 | new_args = append(new_args, os.Args[1:]...) 89 | 90 | switch buffer[0] { 91 | 92 | case protocol.NoGuestCommandRealInit: 93 | // Run our noguest server in a new process. 94 | proc_attr := &syscall.ProcAttr{ 95 | Dir: "/", 96 | Env: os.Environ(), 97 | Files: []uintptr{console.Fd(), 1, 2}, 98 | } 99 | _, err := syscall.ForkExec(os.Args[0], new_args, proc_attr) 100 | if err != nil { 101 | log.Fatal(err) 102 | } 103 | 104 | // Exec our real init here in place. 105 | err = syscall.Exec("/sbin/init", []string{"init"}, os.Environ()) 106 | log.Fatal(err) 107 | 108 | case protocol.NoGuestCommandFakeInit: 109 | // Since we don't have any init to setup basic 110 | // things, like our hostname we do some of that here. 111 | syscall.Sethostname([]byte("novm")) 112 | 113 | default: 114 | // What the heck is this? 115 | log.Fatal(protocol.UnknownCommand) 116 | } 117 | } else { 118 | // Open the defined fd. 119 | console = os.NewFile(uintptr(*server_fd), "console") 120 | } 121 | 122 | // Small victory. 123 | log.Printf("~~~ NOGUEST ~~~") 124 | 125 | // Create our RPC server. 126 | rpc.Run(console) 127 | } 128 | -------------------------------------------------------------------------------- /src/noguest/protocol/command.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package protocol 16 | 17 | const ( 18 | NoGuestCommandFakeInit = 0x1 19 | NoGuestCommandRealInit = 0x2 20 | ) 21 | -------------------------------------------------------------------------------- /src/noguest/protocol/errors.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package protocol 16 | 17 | import ( 18 | "errors" 19 | ) 20 | 21 | var UnknownStatus = errors.New("Unknown status?") 22 | var UnknownCommand = errors.New("Unknown command?") 23 | -------------------------------------------------------------------------------- /src/noguest/protocol/status.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package protocol 16 | 17 | const ( 18 | NoGuestStatusOkay = 0x42 19 | NoGuestStatusFailed = 0x43 20 | ) 21 | -------------------------------------------------------------------------------- /src/noguest/rpc/read.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package rpc 16 | 17 | type ReadCommand struct { 18 | 19 | // The relevant pid. 20 | Pid int `json:"pid"` 21 | 22 | // How much to read? 23 | N uint `json:"n"` 24 | } 25 | 26 | type ReadResult struct { 27 | 28 | // The data read. 29 | Data []byte `json:"data"` 30 | } 31 | 32 | func (server *Server) Read( 33 | read *ReadCommand, 34 | result *ReadResult) error { 35 | 36 | process := server.lookup(read.Pid) 37 | if process == nil { 38 | result.Data = []byte{} 39 | return nil 40 | } 41 | 42 | // Read available data. 43 | buffer := make([]byte, read.N, read.N) 44 | n, err := process.output.Read(buffer) 45 | if n > 0 { 46 | result.Data = buffer[:n] 47 | } else { 48 | result.Data = []byte{} 49 | } 50 | 51 | return err 52 | } 53 | -------------------------------------------------------------------------------- /src/noguest/rpc/server.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package rpc 16 | 17 | import ( 18 | "net/rpc" 19 | "net/rpc/jsonrpc" 20 | "os" 21 | "sync" 22 | "syscall" 23 | "time" 24 | ) 25 | 26 | type Process struct { 27 | 28 | // The files. 29 | input *os.File 30 | output *os.File 31 | 32 | // The start time. 33 | starttime time.Time 34 | 35 | // The exit time. 36 | exittime time.Time 37 | 38 | // Has this exited? 39 | exited bool 40 | 41 | // Our exitcode. 42 | exitcode int 43 | 44 | cond *sync.Cond 45 | } 46 | 47 | func (process *Process) wait() { 48 | process.cond.L.Lock() 49 | defer process.cond.L.Unlock() 50 | 51 | // Until the process is done. 52 | for !process.exited { 53 | process.cond.Wait() 54 | } 55 | } 56 | 57 | func (process *Process) setExitcode(exitcode int) { 58 | process.cond.L.Lock() 59 | defer process.cond.L.Unlock() 60 | 61 | // Set the exitcode. 62 | process.exited = true 63 | process.exitcode = exitcode 64 | process.exittime = time.Now() 65 | process.cond.Broadcast() 66 | } 67 | 68 | func (process *Process) close() { 69 | process.cond.L.Lock() 70 | defer process.cond.L.Unlock() 71 | 72 | // Simulate an exit. 73 | process.setExitcode(1) 74 | process.input.Close() 75 | if process.input != process.output { 76 | process.output.Close() 77 | } 78 | } 79 | 80 | type Server struct { 81 | 82 | // Active processes. 83 | active map[int]*Process 84 | 85 | // Is wait running? 86 | waiting bool 87 | 88 | // Our lock protects 89 | // access to the above map. 90 | mutex sync.Mutex 91 | } 92 | 93 | func (server *Server) clearStale() { 94 | server.mutex.Lock() 95 | defer server.mutex.Unlock() 96 | 97 | for pid, process := range server.active { 98 | // Has this exited more than a minute ago? 99 | if process.exited && 100 | process.exittime.Sub(process.starttime) > time.Minute { 101 | delete(server.active, pid) 102 | process.close() 103 | } 104 | } 105 | } 106 | 107 | func (server *Server) clearPeriodic() { 108 | server.clearStale() 109 | time.AfterFunc(time.Minute, server.clearPeriodic) 110 | } 111 | 112 | func (server *Server) lookup(pid int) *Process { 113 | server.mutex.Lock() 114 | defer server.mutex.Unlock() 115 | return server.active[pid] 116 | } 117 | 118 | func (server *Server) wait() { 119 | 120 | server.mutex.Lock() 121 | if server.waiting { 122 | server.mutex.Unlock() 123 | return 124 | } 125 | server.waiting = true 126 | server.mutex.Unlock() 127 | 128 | var wstatus syscall.WaitStatus 129 | var rusage syscall.Rusage 130 | var last_run bool 131 | for { 132 | pid, err := syscall.Wait4(-1, &wstatus, 0, &rusage) 133 | if err != nil { 134 | if err == syscall.ECHILD { 135 | // Run once more to catch any races. 136 | server.mutex.Lock() 137 | if server.waiting { 138 | server.waiting = false 139 | server.mutex.Unlock() 140 | last_run = true 141 | continue 142 | } else { 143 | server.mutex.Unlock() 144 | return 145 | } 146 | } else { 147 | continue 148 | } 149 | } 150 | if wstatus.Exited() { 151 | process := server.lookup(pid) 152 | if process != nil { 153 | process.setExitcode(wstatus.ExitStatus()) 154 | } 155 | } 156 | if last_run { 157 | break 158 | } 159 | } 160 | } 161 | 162 | func Run(file *os.File) { 163 | 164 | // Create our server. 165 | server := new(Server) 166 | server.active = make(map[int]*Process) 167 | 168 | // Start our periodic clearer. 169 | server.clearPeriodic() 170 | 171 | // Create our RPC server. 172 | codec := jsonrpc.NewServerCodec(file) 173 | rpcserver := rpc.NewServer() 174 | rpcserver.Register(server) 175 | 176 | // Listen for children. 177 | go server.wait() 178 | 179 | // Service requests. 180 | rpcserver.ServeCodec(codec) 181 | } 182 | -------------------------------------------------------------------------------- /src/noguest/rpc/wait.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package rpc 16 | 17 | type WaitCommand struct { 18 | 19 | // The relevant pid. 20 | Pid int `json:"pid"` 21 | } 22 | 23 | type WaitResult struct { 24 | 25 | // The exit code. 26 | // (If > 0 then this event is an exit event). 27 | Exitcode int `json:"exitcode"` 28 | } 29 | 30 | func (server *Server) Wait( 31 | wait *WaitCommand, 32 | result *WaitResult) error { 33 | 34 | process := server.lookup(wait.Pid) 35 | if process == nil { 36 | result.Exitcode = -1 37 | return nil 38 | } 39 | 40 | process.wait() 41 | result.Exitcode = process.exitcode 42 | return nil 43 | } 44 | -------------------------------------------------------------------------------- /src/noguest/rpc/write.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package rpc 16 | 17 | type WriteCommand struct { 18 | 19 | // The relevant pid. 20 | Pid int `json:"pid"` 21 | 22 | // The write. 23 | Data []byte `json:"data"` 24 | } 25 | 26 | type WriteResult struct { 27 | 28 | // How much was written? 29 | Written int `json:"n"` 30 | } 31 | 32 | func (server *Server) Write( 33 | write *WriteCommand, 34 | out *WriteResult) error { 35 | 36 | process := server.lookup(write.Pid) 37 | if process == nil || write.Data == nil { 38 | out.Written = -1 39 | return nil 40 | } 41 | 42 | // Push the write. 43 | for len(write.Data) > 0 { 44 | n, err := process.input.Write(write.Data) 45 | out.Written += n 46 | write.Data = write.Data[n:] 47 | if err != nil { 48 | return err 49 | } 50 | } 51 | 52 | return nil 53 | } 54 | -------------------------------------------------------------------------------- /src/novmm/control/errors.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package control 16 | 17 | import ( 18 | "errors" 19 | ) 20 | 21 | var InvalidControlSocket = errors.New("Invalid control socket?") 22 | var InternalGuestError = errors.New("Internal guest error?") 23 | -------------------------------------------------------------------------------- /src/novmm/control/guest.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package control 16 | 17 | import ( 18 | "net/rpc" 19 | "net/rpc/jsonrpc" 20 | "noguest/protocol" 21 | ) 22 | 23 | func (control *Control) init() { 24 | 25 | buffer := make([]byte, 1, 1) 26 | 27 | // Read our control byte back. 28 | n, err := control.proxy.Read(buffer) 29 | if n == 1 && err == nil { 30 | switch buffer[0] { 31 | case protocol.NoGuestStatusOkay: 32 | break 33 | case protocol.NoGuestStatusFailed: 34 | // Something went horribly wrong. 35 | control.client_res <- InternalGuestError 36 | return 37 | default: 38 | // This isn't good, who knows what happened? 39 | control.client_res <- protocol.UnknownStatus 40 | return 41 | } 42 | } else if err != nil { 43 | // An actual error. 44 | control.client_res <- err 45 | return 46 | } 47 | 48 | // Send our control byte to noguest. 49 | // This essentially controls how the guest 50 | // will proceed during execution. If it is the 51 | // real init process, it will wait for run commands 52 | // and execute the given processes inside the VM. 53 | // If it is not the real init process, it will fork 54 | // and execute the real init before starting to 55 | // process any other RPC commands. 56 | if control.real_init { 57 | buffer[0] = protocol.NoGuestCommandRealInit 58 | } else { 59 | buffer[0] = protocol.NoGuestCommandFakeInit 60 | } 61 | n, err = control.proxy.Write(buffer) 62 | if n != 1 { 63 | // Can't send anything? 64 | control.client_res <- InternalGuestError 65 | return 66 | } 67 | 68 | // Looks like we're good. 69 | control.client_res <- nil 70 | } 71 | 72 | func (control *Control) barrier() { 73 | control.client_err = <-control.client_res 74 | control.client_codec = jsonrpc.NewClientCodec(control.proxy) 75 | control.client = rpc.NewClientWithCodec(control.client_codec) 76 | } 77 | 78 | func (control *Control) Ready() (*rpc.Client, error) { 79 | control.client_once.Do(control.barrier) 80 | return control.client, control.client_err 81 | } 82 | -------------------------------------------------------------------------------- /src/novmm/control/rpc_basic.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package control 16 | 17 | // 18 | // High-level rpcs. 19 | // 20 | 21 | func (rpc *Rpc) Pause(nopin *Nop, nopout *Nop) error { 22 | return rpc.vm.Pause(true) 23 | } 24 | 25 | func (rpc *Rpc) Unpause(nopin *Nop, nopout *Nop) error { 26 | return rpc.vm.Unpause(true) 27 | } 28 | -------------------------------------------------------------------------------- /src/novmm/control/rpc_device.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package control 16 | 17 | import ( 18 | "regexp" 19 | ) 20 | 21 | // 22 | // Low-level device controls. 23 | // 24 | 25 | type DeviceSettings struct { 26 | // Name. 27 | Name string `json:"name"` 28 | 29 | // Drvier. 30 | Driver string `json:"driver"` 31 | 32 | // Debug? 33 | Debug bool `json:"debug"` 34 | 35 | // Pause? 36 | Paused bool `json:"paused"` 37 | } 38 | 39 | func (rpc *Rpc) Device(settings *DeviceSettings, nop *Nop) error { 40 | 41 | rn, err := regexp.Compile(settings.Name) 42 | if err != nil { 43 | return err 44 | } 45 | 46 | rd, err := regexp.Compile(settings.Driver) 47 | if err != nil { 48 | return err 49 | } 50 | 51 | for _, device := range rpc.model.Devices() { 52 | 53 | if rn.MatchString(device.Name()) && 54 | rd.MatchString(device.Driver()) { 55 | 56 | device.SetDebugging(settings.Debug) 57 | 58 | if settings.Paused { 59 | err = device.Pause(true) 60 | } else { 61 | err = device.Unpause(true) 62 | } 63 | 64 | if err != nil { 65 | break 66 | } 67 | } 68 | } 69 | 70 | return err 71 | } 72 | -------------------------------------------------------------------------------- /src/novmm/control/rpc_state.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package control 16 | 17 | // 18 | // State-related rpcs. 19 | // 20 | 21 | func (rpc *Rpc) State(nop *Nop, res *State) error { 22 | 23 | state, err := SaveState(rpc.vm, rpc.model) 24 | if err != nil { 25 | return err 26 | } 27 | 28 | // Save our state. 29 | res.Vcpus = state.Vcpus 30 | res.Devices = state.Devices 31 | 32 | return err 33 | } 34 | 35 | func (rpc *Rpc) Reload(in *Nop, out *Nop) error { 36 | 37 | // Pause the vm. 38 | // This is kept pausing for the entire reload(). 39 | err := rpc.vm.Pause(false) 40 | if err != nil { 41 | return err 42 | } 43 | defer rpc.vm.Unpause(false) 44 | 45 | // Save a copy of the current state. 46 | state, err := SaveState(rpc.vm, rpc.model) 47 | if err != nil { 48 | return err 49 | } 50 | 51 | // Reload all vcpus. 52 | for i, vcpuspec := range state.Vcpus { 53 | err := rpc.vm.Vcpus()[i].Load(vcpuspec) 54 | if err != nil { 55 | return err 56 | } 57 | } 58 | 59 | // Reload all device state. 60 | return rpc.model.Load(rpc.vm) 61 | } 62 | -------------------------------------------------------------------------------- /src/novmm/control/rpc_trace.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package control 16 | 17 | // 18 | // Tracing & debug controls. 19 | // 20 | 21 | type TraceSettings struct { 22 | // Tracing? 23 | Enable bool `json:"enable"` 24 | } 25 | 26 | func (rpc *Rpc) Trace(settings *TraceSettings, nop *Nop) error { 27 | if settings.Enable { 28 | rpc.tracer.Enable() 29 | } else { 30 | rpc.tracer.Disable() 31 | } 32 | 33 | return nil 34 | } 35 | -------------------------------------------------------------------------------- /src/novmm/control/rpc_types.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package control 16 | 17 | import ( 18 | "novmm/loader" 19 | "novmm/machine" 20 | "novmm/platform" 21 | ) 22 | 23 | // 24 | // Rpc -- 25 | // 26 | // This is basic state provided to the 27 | // Rpc interface. All Rpc functions have 28 | // access to this state (but nothing else). 29 | // 30 | 31 | type Rpc struct { 32 | // Our device model. 33 | model *machine.Model 34 | 35 | // Our underlying Vm object. 36 | vm *platform.Vm 37 | 38 | // Our tracer. 39 | tracer *loader.Tracer 40 | } 41 | 42 | func NewRpc( 43 | model *machine.Model, 44 | vm *platform.Vm, 45 | tracer *loader.Tracer) *Rpc { 46 | 47 | return &Rpc{ 48 | model: model, 49 | vm: vm, 50 | tracer: tracer, 51 | } 52 | } 53 | 54 | // 55 | // The Noop -- 56 | // 57 | // Many of our operations do not require 58 | // a specific parameter or a specific return. 59 | // 60 | type Nop struct{} 61 | -------------------------------------------------------------------------------- /src/novmm/control/rpc_vcpu.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package control 16 | 17 | import ( 18 | "syscall" 19 | ) 20 | 21 | // 22 | // Low-level vcpu controls. 23 | // 24 | 25 | type VcpuSettings struct { 26 | // Which vcpu? 27 | Id int `json:"id"` 28 | 29 | // Single stepping? 30 | Step bool `json:"step"` 31 | 32 | // Paused? 33 | Paused bool `json:"paused"` 34 | } 35 | 36 | func (rpc *Rpc) Vcpu(settings *VcpuSettings, nop *Nop) error { 37 | // A valid vcpu? 38 | vcpus := rpc.vm.Vcpus() 39 | if settings.Id >= len(vcpus) { 40 | return syscall.EINVAL 41 | } 42 | 43 | // Grab our specific vcpu. 44 | vcpu := vcpus[settings.Id] 45 | 46 | // Ensure steping is as expected. 47 | err := vcpu.SetStepping(settings.Step) 48 | if err != nil { 49 | return err 50 | } 51 | 52 | // Ensure that the vcpu is paused/unpaused. 53 | if settings.Paused { 54 | err = vcpu.Pause(true) 55 | } else { 56 | err = vcpu.Unpause(true) 57 | } 58 | 59 | // Done. 60 | return err 61 | } 62 | -------------------------------------------------------------------------------- /src/novmm/control/state.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package control 16 | 17 | import ( 18 | "novmm/machine" 19 | "novmm/platform" 20 | ) 21 | 22 | // 23 | // State. 24 | // 25 | 26 | type State struct { 27 | // Our device state. 28 | // Note that we only encode state associated with 29 | // specific devices. The model type is a generic wrapped 30 | // around devices which *may* encode additional state, 31 | // but all the state associated with the model should be 32 | // regenerated on startup. 33 | Devices []machine.DeviceInfo `json:"devices,omitempty"` 34 | 35 | // Our vcpu state. 36 | // Similarly, this should encode all the state associated 37 | // with the underlying VM. If we have other internal platform 38 | // devices (such as APICs or PITs) then these should be somehow 39 | // encoded as generic devices. 40 | Vcpus []platform.VcpuInfo `json:"vcpus,omitempty"` 41 | } 42 | 43 | func SaveState(vm *platform.Vm, model *machine.Model) (State, error) { 44 | 45 | // Pause the vm. 46 | // NOTE: Our model will also be stopped automatically 47 | // with model.DeviceInfo() below, but we manually pause 48 | // the Vcpus here in order to ensure they are completely 49 | // stopped prior to saving all device state. 50 | err := vm.Pause(false) 51 | if err != nil { 52 | return State{}, err 53 | } 54 | defer vm.Unpause(false) 55 | 56 | // Grab our vcpu states. 57 | vcpus, err := vm.VcpuInfo() 58 | if err != nil { 59 | return State{}, err 60 | } 61 | 62 | // Grab our devices. 63 | // NOTE: This should block until devices have 64 | // actually quiesed (finished processing outstanding 65 | // requests generated by the VCPUs). 66 | devices, err := model.DeviceInfo(vm) 67 | if err != nil { 68 | return State{}, err 69 | } 70 | 71 | // Done. 72 | return State{Vcpus: vcpus, Devices: devices}, nil 73 | } 74 | -------------------------------------------------------------------------------- /src/novmm/errors.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "errors" 19 | ) 20 | 21 | var ExitWithoutReason = errors.New("Exit without reason?") 22 | var NoVcpus = errors.New("No vcpus?") 23 | -------------------------------------------------------------------------------- /src/novmm/loader/elf_load.c: -------------------------------------------------------------------------------- 1 | /* 2 | * elf_load.c 3 | * 4 | * Implementation of a simple linux loader. 5 | * 6 | * Note that this is only part of the implementation, 7 | * I've managed to keep most of the bit twiddling in 8 | * go itself -- this is simply easier because of the 9 | * direct access to the ELF type definitions. 10 | * 11 | * Copyright 2014 Google Inc. All rights reserved. 12 | * 13 | * Licensed under the Apache License, Version 2.0 (the "License"); 14 | * you may not use this file except in compliance with the License. 15 | * You may obtain a copy of the License at 16 | * 17 | * http://www.apache.org/licenses/LICENSE-2.0 18 | * 19 | * Unless required by applicable law or agreed to in writing, software 20 | * distributed under the License is distributed on an "AS IS" BASIS, 21 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 22 | * See the License for the specific language governing permissions and 23 | * limitations under the License. 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #define ELF_LOAD(phdr, phnum, elf_start, self) \ 32 | do { \ 33 | int i; \ 34 | for(i=0; i < phnum; i++) { \ 35 | int r; \ 36 | if(phdr[i].p_type != PT_LOAD) \ 37 | continue; \ 38 | if(phdr[i].p_filesz > phdr[i].p_memsz) \ 39 | return -EINVAL; \ 40 | if(!phdr[i].p_filesz) \ 41 | return -EINVAL; \ 42 | r = doLoad( \ 43 | self, \ 44 | phdr[i].p_paddr, \ 45 | (char*)elf_start + phdr[i].p_offset, \ 46 | phdr[i].p_filesz); \ 47 | if(r != 0) \ 48 | return r; \ 49 | } \ 50 | return 0; \ 51 | } while(0) 52 | 53 | int 54 | elf32_load( 55 | Elf32_Phdr *phdr, 56 | int phnum, 57 | void *elf_start, 58 | void *self) 59 | { 60 | ELF_LOAD(phdr, phnum, elf_start, self); 61 | } 62 | 63 | int 64 | elf64_load( 65 | Elf64_Phdr *phdr, 66 | int phnum, 67 | void *elf_start, 68 | void *self) 69 | { 70 | ELF_LOAD(phdr, phnum, elf_start, self); 71 | } 72 | 73 | long long 74 | elf_load( 75 | char *elf_start, 76 | void *self, 77 | int *is_64bit) 78 | { 79 | Elf32_Ehdr *hdr32 = (Elf32_Ehdr*)elf_start; 80 | Elf64_Ehdr *hdr64 = (Elf64_Ehdr*)elf_start; 81 | 82 | if (hdr32->e_ident[EI_MAG0] != ELFMAG0 || 83 | hdr32->e_ident[EI_MAG1] != ELFMAG1 || 84 | hdr32->e_ident[EI_MAG2] != ELFMAG2 || 85 | hdr32->e_ident[EI_MAG3] != ELFMAG3) 86 | return -EINVAL; 87 | 88 | if (hdr32->e_ident[4] == ELFCLASS32) { 89 | int r = elf32_load( 90 | (Elf32_Phdr *)(elf_start + hdr32->e_phoff), 91 | hdr32->e_phnum, 92 | elf_start, 93 | self); 94 | if (r<0) 95 | return r; 96 | *is_64bit = 0; 97 | return hdr32->e_entry; 98 | 99 | } else if (hdr64->e_ident[4] == ELFCLASS64) { 100 | int r = elf64_load( 101 | (Elf64_Phdr *)(elf_start + hdr64->e_phoff), 102 | hdr64->e_phnum, 103 | elf_start, 104 | self); 105 | if (r<0) 106 | return r; 107 | *is_64bit = 1; 108 | return hdr64->e_entry; 109 | 110 | } else { 111 | return -EINVAL; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/novmm/loader/elf_load.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package loader 16 | 17 | /* 18 | #include 19 | #include "elf_load.h" 20 | */ 21 | import "C" 22 | 23 | import ( 24 | "log" 25 | "novmm/machine" 26 | "novmm/platform" 27 | "syscall" 28 | "unsafe" 29 | ) 30 | 31 | //export doLoad 32 | func doLoad( 33 | self unsafe.Pointer, 34 | offset C.size_t, 35 | source unsafe.Pointer, 36 | length C.size_t) C.int { 37 | 38 | model := (*machine.Model)(self) 39 | 40 | // Bump up the size to the end of the page. 41 | new_length := platform.Align(uint64(length), platform.PageSize, true) 42 | 43 | // Allocate the backing data. 44 | data, err := model.Map( 45 | machine.MemoryTypeUser, 46 | platform.Paddr(offset), 47 | new_length, 48 | true) 49 | if err != nil { 50 | // Things are broken. 51 | log.Print("Error during ElfLoad: ", err) 52 | return -C.int(syscall.EINVAL) 53 | } 54 | 55 | // Copy the data in. 56 | C.memcpy(unsafe.Pointer(&data[0]), source, length) 57 | 58 | // All good. 59 | return 0 60 | } 61 | 62 | func ElfLoad( 63 | data []byte, 64 | model *machine.Model) (uint64, bool, error) { 65 | 66 | // Do the load. 67 | var is_64bit C.int 68 | entry_point := C.elf_load( 69 | unsafe.Pointer(&data[0]), 70 | unsafe.Pointer(model), 71 | &is_64bit) 72 | if entry_point < 0 { 73 | return 0, false, syscall.Errno(-entry_point) 74 | } 75 | 76 | // Looks like we're okay. 77 | return uint64(entry_point), int(is_64bit) == 1, nil 78 | } 79 | -------------------------------------------------------------------------------- /src/novmm/loader/elf_load.h: -------------------------------------------------------------------------------- 1 | /* 2 | * elf_load.h 3 | * 4 | * Copyright 2014 Google Inc. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include 20 | 21 | extern int doLoad(void *self, size_t offset, void *source, size_t length); 22 | 23 | long long elf_load(void *elf_start, void *self, int *is_64bit); 24 | -------------------------------------------------------------------------------- /src/novmm/loader/errors.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package loader 16 | 17 | import ( 18 | "errors" 19 | ) 20 | 21 | // Linux errors. 22 | var InvalidSetupHeader = errors.New("Setup header past page boundary?") 23 | -------------------------------------------------------------------------------- /src/novmm/loader/linux_setup.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //+build i386 amd64 16 | package loader 17 | 18 | /* 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | // E820 codes. 25 | const int E820Ram = E820_RAM; 26 | const int E820Reserved = E820_RESERVED; 27 | const int E820Acpi = E820_ACPI; 28 | 29 | // Our E820 map. 30 | static inline void e820_set_count( 31 | struct boot_params* boot, 32 | int count) { 33 | 34 | boot->e820_entries = count; 35 | } 36 | static inline void e820_set_region( 37 | struct boot_params* boot, 38 | int index, 39 | __u64 start, 40 | __u64 size, 41 | __u8 type) { 42 | 43 | boot->e820_map[index].addr = start; 44 | boot->e820_map[index].size = size; 45 | boot->e820_map[index].type = type; 46 | } 47 | static inline void set_header( 48 | struct boot_params* boot, 49 | __u64 initrd_addr, 50 | __u64 initrd_len, 51 | __u64 cmdline_addr) { 52 | 53 | boot->hdr.vid_mode = 0xffff; 54 | boot->hdr.type_of_loader = 0xff; 55 | boot->hdr.loadflags = 0; 56 | boot->hdr.setup_move_size = 0; 57 | boot->hdr.ramdisk_image = initrd_addr; 58 | boot->hdr.ramdisk_size = initrd_len; 59 | boot->hdr.heap_end_ptr = 0; 60 | boot->hdr.cmd_line_ptr = cmdline_addr; 61 | boot->hdr.setup_data = 0; 62 | } 63 | */ 64 | import "C" 65 | 66 | import ( 67 | "novmm/machine" 68 | "novmm/platform" 69 | "unsafe" 70 | ) 71 | 72 | func SetupLinuxBootParams( 73 | model *machine.Model, 74 | boot_params_data []byte, 75 | orig_boot_params_data []byte, 76 | cmdline_addr platform.Paddr, 77 | initrd_addr platform.Paddr, 78 | initrd_len uint64) error { 79 | 80 | // Grab a reference to our boot params struct. 81 | boot_params := (*C.struct_boot_params)(unsafe.Pointer(&boot_params_data[0])) 82 | 83 | // The setup header. 84 | // First step is to copy the existing setup_header 85 | // out of the given kernel image. We copy only the 86 | // header, and not the rest of the setup page. 87 | setup_start := 0x01f1 88 | setup_end := 0x0202 + int(orig_boot_params_data[0x0201]) 89 | if setup_end > platform.PageSize { 90 | return InvalidSetupHeader 91 | } 92 | C.memcpy( 93 | unsafe.Pointer(&boot_params_data[setup_start]), 94 | unsafe.Pointer(&orig_boot_params_data[setup_start]), 95 | C.size_t(setup_end-setup_start)) 96 | 97 | // Setup our BIOS memory map. 98 | // NOTE: We have to do this via C bindings. This is really 99 | // annoying, but basically because of the unaligned structures 100 | // in the struct_boot_params, the Go code generated here is 101 | // actually *incompatible* with the actual C layout. 102 | 103 | // First, the count. 104 | C.e820_set_count(boot_params, C.int(len(model.MemoryMap))) 105 | 106 | // Then, fill out the region information. 107 | for index, region := range model.MemoryMap { 108 | 109 | var memtype C.int 110 | switch region.MemoryType { 111 | case machine.MemoryTypeUser: 112 | memtype = C.E820Ram 113 | case machine.MemoryTypeReserved: 114 | memtype = C.E820Reserved 115 | case machine.MemoryTypeSpecial: 116 | memtype = C.E820Reserved 117 | case machine.MemoryTypeAcpi: 118 | memtype = C.E820Acpi 119 | } 120 | 121 | C.e820_set_region( 122 | boot_params, 123 | C.int(index), 124 | C.__u64(region.Start), 125 | C.__u64(region.Size), 126 | C.__u8(memtype)) 127 | } 128 | 129 | // Set necessary setup header bits. 130 | C.set_header( 131 | boot_params, 132 | C.__u64(initrd_addr), 133 | C.__u64(initrd_len), 134 | C.__u64(cmdline_addr)) 135 | 136 | // All done! 137 | return nil 138 | } 139 | -------------------------------------------------------------------------------- /src/novmm/loader/sysmap.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package loader 16 | 17 | import ( 18 | "novmm/platform" 19 | ) 20 | 21 | type SystemMap interface { 22 | Lookup(addr platform.Vaddr) (string, uint64) 23 | } 24 | 25 | type Convention struct { 26 | instruction platform.Register 27 | arguments []platform.Register 28 | rvalue platform.Register 29 | stack platform.Register 30 | } 31 | -------------------------------------------------------------------------------- /src/novmm/loader/trace.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package loader 16 | 17 | import ( 18 | "fmt" 19 | "log" 20 | "novmm/platform" 21 | "strings" 22 | ) 23 | 24 | type Tracer struct { 25 | sysmap SystemMap 26 | convention *Convention 27 | last_addr platform.Vaddr 28 | last_fname string 29 | enabled bool 30 | } 31 | 32 | func NewTracer(sysmap SystemMap, convention *Convention) *Tracer { 33 | return &Tracer{ 34 | sysmap: sysmap, 35 | convention: convention, 36 | last_addr: 0, 37 | last_fname: "", 38 | enabled: false, 39 | } 40 | } 41 | 42 | func (tracer *Tracer) Enable() { 43 | tracer.enabled = true 44 | } 45 | 46 | func (tracer *Tracer) Disable() { 47 | tracer.enabled = false 48 | } 49 | 50 | func (tracer *Tracer) IsEnabled() bool { 51 | return tracer.enabled 52 | } 53 | 54 | func (tracer *Tracer) toPaddr( 55 | vcpu *platform.Vcpu, 56 | reg platform.RegisterValue) string { 57 | 58 | phys_addr, valid, _, _, err := vcpu.Translate(platform.Vaddr(reg)) 59 | if err != nil { 60 | return "%x->??" 61 | } 62 | 63 | if valid { 64 | return fmt.Sprintf("%x->%x", reg, phys_addr) 65 | } 66 | 67 | return fmt.Sprintf("%x", reg) 68 | } 69 | 70 | func (tracer *Tracer) Trace(vcpu *platform.Vcpu, step bool) error { 71 | 72 | // Are we on? 73 | if !tracer.enabled { 74 | return nil 75 | } 76 | 77 | // Get the current instruction. 78 | addr, err := vcpu.GetRegister(tracer.convention.instruction) 79 | if err != nil { 80 | return err 81 | } 82 | 83 | // Skip duplicates (only if stepping is on). 84 | if step && platform.Vaddr(addr) == tracer.last_addr { 85 | return nil 86 | } 87 | 88 | // Lookup the current instruction. 89 | var fname string 90 | var offset uint64 91 | if tracer.sysmap != nil { 92 | fname, offset = tracer.sysmap.Lookup(platform.Vaddr(addr)) 93 | } 94 | 95 | // Get the stack depth. 96 | stack, err := vcpu.GetRegister(tracer.convention.stack) 97 | if err != nil { 98 | return err 99 | } 100 | 101 | // Print the return value if applicable. 102 | if step && 103 | fname != tracer.last_fname && 104 | tracer.last_addr != 0 { 105 | 106 | rval, err := vcpu.GetRegister(tracer.convention.rvalue) 107 | if err != nil { 108 | return err 109 | } 110 | log.Printf(" trace: [%08x] %s => %s ?", 111 | stack, 112 | tracer.last_fname, 113 | tracer.toPaddr(vcpu, rval)) 114 | 115 | // Save the current. 116 | tracer.last_fname = fname 117 | } 118 | 119 | // Get a physical address string. 120 | rip_phys_str := tracer.toPaddr(vcpu, addr) 121 | 122 | if fname != "" { 123 | if offset == 0 { 124 | num_args := len(tracer.convention.arguments) 125 | arg_vals := make([]string, num_args, num_args) 126 | for i, reg := range tracer.convention.arguments { 127 | reg_val, err := vcpu.GetRegister(reg) 128 | if err != nil { 129 | arg_vals[i] = fmt.Sprintf("??") 130 | continue 131 | } 132 | arg_vals[i] = tracer.toPaddr(vcpu, reg_val) 133 | } 134 | log.Printf(" trace: [%08x] %s:%s(%s)", 135 | stack, 136 | fname, 137 | rip_phys_str, 138 | strings.Join(arg_vals, ",")) 139 | } else { 140 | log.Printf(" trace: [%08x] %s:%s ... +%x", 141 | stack, 142 | fname, 143 | rip_phys_str, 144 | offset) 145 | } 146 | } else { 147 | log.Printf(" trace: ??:%s", rip_phys_str) 148 | } 149 | 150 | // We're okay. 151 | tracer.last_addr = platform.Vaddr(addr) 152 | return nil 153 | } 154 | -------------------------------------------------------------------------------- /src/novmm/loop.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "log" 19 | "novmm/loader" 20 | "novmm/machine" 21 | "novmm/platform" 22 | "runtime" 23 | ) 24 | 25 | func Loop( 26 | vm *platform.Vm, 27 | vcpu *platform.Vcpu, 28 | model *machine.Model, 29 | tracer *loader.Tracer) error { 30 | 31 | // It's not really kosher to switch threads constantly when running a 32 | // KVM VCPU. So we simply lock this goroutine to a single system 33 | // thread. That way we know it won't be bouncing around. 34 | runtime.LockOSThread() 35 | defer runtime.UnlockOSThread() 36 | 37 | log.Printf("Vcpu[%d] running.", vcpu.Id) 38 | 39 | for { 40 | // Enter the guest. 41 | err := vcpu.Run() 42 | 43 | // Trace if requested. 44 | trace_err := tracer.Trace(vcpu, vcpu.IsStepping()) 45 | if trace_err != nil { 46 | return trace_err 47 | } 48 | 49 | // No reason for exit? 50 | if err == nil { 51 | return ExitWithoutReason 52 | } 53 | 54 | // Handle the error. 55 | switch err.(type) { 56 | case *platform.ExitPio: 57 | err = model.HandlePio(vm, err.(*platform.ExitPio)) 58 | 59 | case *platform.ExitMmio: 60 | err = model.HandleMmio(vm, err.(*platform.ExitMmio)) 61 | 62 | case *platform.ExitDebug: 63 | err = nil 64 | 65 | case *platform.ExitShutdown: 66 | // Vcpu shutdown. 67 | return nil 68 | } 69 | 70 | // Error handling the exit. 71 | if err != nil { 72 | return err 73 | } 74 | } 75 | 76 | // Unreachable. 77 | return nil 78 | } 79 | -------------------------------------------------------------------------------- /src/novmm/machine/acpi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * acpi.h 3 | * 4 | * Copyright 2014 Google Inc. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include 20 | 21 | long build_rsdp(void* start, __u32 rsdt_address, __u64 xsdt_address); 22 | 23 | long build_rsdt(void* start, __u32 madt_address); 24 | long build_xsdt(void* start, __u64 madt_address); 25 | 26 | long build_dsdt(void* start); 27 | 28 | long build_madt_device_lapic(void* start, __u8 processor_id, __u8 apic_id); 29 | long build_madt_device_ioapic(void* start, __u8 ioapic_id, __u32 address, __u32 interrupt); 30 | long build_madt(void* start, __u32 lapic_address, int vcpus, __u32 ioapic_address, __u32 ioapic_interrupt); 31 | -------------------------------------------------------------------------------- /src/novmm/machine/apic.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package machine 16 | 17 | import ( 18 | "novmm/platform" 19 | ) 20 | 21 | type Apic struct { 22 | BaseDevice 23 | 24 | // Our addresses. 25 | // At the moment, these are at fixed address. 26 | // But just check that they meet expectations. 27 | IOApic platform.Paddr `json:"ioapic"` 28 | LApic platform.Paddr `json:"lapic"` 29 | 30 | // Our platform APIC. 31 | State platform.IrqChip `json:"state"` 32 | } 33 | 34 | func NewApic(info *DeviceInfo) (Device, error) { 35 | 36 | apic := new(Apic) 37 | 38 | // Figure out our Apic addresses. 39 | // See the note above re: fixed addresses. 40 | apic.IOApic = platform.IOApic() 41 | apic.LApic = platform.LApic() 42 | 43 | return apic, apic.init(info) 44 | } 45 | 46 | func (apic *Apic) Attach(vm *platform.Vm, model *Model) error { 47 | 48 | // Reserve our IOApic and LApic. 49 | err := model.Reserve( 50 | vm, 51 | apic, 52 | MemoryTypeReserved, 53 | apic.IOApic, 54 | platform.PageSize, 55 | nil) 56 | if err != nil { 57 | return err 58 | } 59 | err = model.Reserve( 60 | vm, 61 | apic, 62 | MemoryTypeReserved, 63 | apic.LApic, 64 | platform.PageSize, 65 | nil) 66 | if err != nil { 67 | return err 68 | } 69 | 70 | // Create our irqchip. 71 | err = vm.CreateIrqChip() 72 | if err != nil { 73 | return err 74 | } 75 | 76 | // We're good. 77 | return nil 78 | } 79 | 80 | func (apic *Apic) Save(vm *platform.Vm) error { 81 | 82 | var err error 83 | 84 | // Save our IrqChip state. 85 | apic.State, err = vm.GetIrqChip() 86 | if err != nil { 87 | return err 88 | } 89 | 90 | // We're good. 91 | return nil 92 | } 93 | 94 | func (apic *Apic) Load(vm *platform.Vm) error { 95 | // Load state. 96 | return vm.SetIrqChip(apic.State) 97 | } 98 | -------------------------------------------------------------------------------- /src/novmm/machine/bios.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package machine 16 | 17 | import ( 18 | "novmm/platform" 19 | ) 20 | 21 | type Bios struct { 22 | BaseDevice 23 | 24 | // Our reserved TSS (for Intel VTX). 25 | TSSAddr platform.Paddr `json:"tss"` 26 | } 27 | 28 | func NewBios(info *DeviceInfo) (Device, error) { 29 | bios := new(Bios) 30 | 31 | // Sensible default. 32 | bios.TSSAddr = 0xfffbc000 33 | 34 | return bios, bios.init(info) 35 | } 36 | 37 | func (bios *Bios) Attach(vm *platform.Vm, model *Model) error { 38 | 39 | // Reserve our basic "BIOS" memory. 40 | // This is done simply to match expectations. 41 | // Nothing should be allocated in the first page. 42 | err := model.Reserve( 43 | vm, 44 | bios, 45 | MemoryTypeReserved, 46 | platform.Paddr(0), // Start. 47 | platform.PageSize, // Size. 48 | nil) 49 | if err != nil { 50 | return err 51 | } 52 | 53 | // Now reserve our TSS. 54 | err = model.Reserve( 55 | vm, 56 | bios, 57 | MemoryTypeSpecial, 58 | bios.TSSAddr, 59 | vm.SizeSpecialMemory(), 60 | nil) 61 | if err != nil { 62 | return err 63 | } 64 | 65 | // Finish the region. 66 | tss_end := bios.TSSAddr.After(vm.SizeSpecialMemory()) 67 | err = model.Reserve( 68 | vm, 69 | bios, 70 | MemoryTypeReserved, 71 | tss_end, 72 | uint64(platform.Paddr(0x100000000)-tss_end), 73 | nil) 74 | if err != nil { 75 | return err 76 | } 77 | 78 | // We're good. 79 | return nil 80 | } 81 | -------------------------------------------------------------------------------- /src/novmm/machine/cache.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package machine 16 | 17 | import ( 18 | "novmm/platform" 19 | ) 20 | 21 | // 22 | // I/O cache -- 23 | // 24 | // Our I/O cache stores paddr => handler mappings. 25 | // 26 | // When a device returns a SaveIO error, we actually try to 27 | // setup an EventFD for that specific addr and value. This 28 | // will avoid having to go through the cache every time. We 29 | // do this only after accruing sufficient hits however, in 30 | // order to avoid wasting eventfds on devices that only hit 31 | // a few times (like an unused NIC, for example). 32 | // 33 | // See eventfd.go for the save() function where this is done. 34 | 35 | type IoCache struct { 36 | 37 | // Our set of I/O handlers. 38 | handlers []IoHandlers 39 | 40 | // Our I/O cache. 41 | memory map[platform.Paddr]*IoHandler 42 | 43 | // Our hits. 44 | hits map[platform.Paddr]uint64 45 | 46 | // Is this a Pio cache? 47 | is_pio bool 48 | } 49 | 50 | func (cache *IoCache) lookup(addr platform.Paddr) *IoHandler { 51 | 52 | handler, ok := cache.memory[addr] 53 | if ok { 54 | cache.hits[addr] += 1 55 | return handler 56 | } 57 | 58 | // See if we can find a matching device. 59 | for _, handlers := range cache.handlers { 60 | for port_region, handler := range handlers { 61 | if port_region.Contains(addr, 1) { 62 | cache.memory[addr] = handler 63 | cache.hits[addr] += 1 64 | return handler 65 | } 66 | } 67 | } 68 | 69 | // Nothing found. 70 | return nil 71 | } 72 | 73 | func NewIoCache(handlers []IoHandlers, is_pio bool) *IoCache { 74 | return &IoCache{ 75 | handlers: handlers, 76 | memory: make(map[platform.Paddr]*IoHandler), 77 | hits: make(map[platform.Paddr]uint64), 78 | is_pio: is_pio, 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/novmm/machine/clock.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package machine 16 | 17 | import ( 18 | "novmm/platform" 19 | ) 20 | 21 | type Clock struct { 22 | BaseDevice 23 | 24 | // Our clock state. 25 | Clock platform.Clock `json:"clock"` 26 | } 27 | 28 | func NewClock(info *DeviceInfo) (Device, error) { 29 | clock := new(Clock) 30 | return clock, clock.init(info) 31 | } 32 | 33 | func (clock *Clock) Attach(vm *platform.Vm, model *Model) error { 34 | // We're good. 35 | return nil 36 | } 37 | 38 | func (clock *Clock) Save(vm *platform.Vm) error { 39 | 40 | var err error 41 | 42 | // Save our clock state. 43 | clock.Clock, err = vm.GetClock() 44 | if err != nil { 45 | return err 46 | } 47 | 48 | // We're good. 49 | return nil 50 | } 51 | 52 | func (clock *Clock) Load(vm *platform.Vm) error { 53 | // Load state. 54 | return vm.SetClock(clock.Clock) 55 | } 56 | -------------------------------------------------------------------------------- /src/novmm/machine/drivers.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package machine 16 | 17 | // A driver load function. 18 | type Driver func(info *DeviceInfo) (Device, error) 19 | 20 | // All available device drivers. 21 | var drivers = map[string]Driver{ 22 | "bios": NewBios, 23 | "apic": NewApic, 24 | "pit": NewPit, 25 | "acpi": NewAcpi, 26 | "rtc": NewRtc, 27 | "clock": NewClock, 28 | "uart": NewUart, 29 | "pci-bus": NewPciBus, 30 | "pci-hostbridge": NewPciHostBridge, 31 | "user-memory": NewUserMemory, 32 | "virtio-pci-block": NewVirtioPciBlock, 33 | "virtio-mmio-block": NewVirtioMmioBlock, 34 | "virtio-pci-console": NewVirtioPciConsole, 35 | "virtio-mmio-console": NewVirtioMmioConsole, 36 | "virtio-pci-net": NewVirtioPciNet, 37 | "virtio-mmio-net": NewVirtioMmioNet, 38 | "virtio-pci-fs": NewVirtioPciFs, 39 | "virtio-mmio-fs": NewVirtioMmioFs, 40 | } 41 | -------------------------------------------------------------------------------- /src/novmm/machine/entry.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package machine 16 | 17 | import ( 18 | "novmm/platform" 19 | ) 20 | 21 | func (model *Model) Handle( 22 | vm *platform.Vm, 23 | cache *IoCache, 24 | handler *IoHandler, 25 | ioevent IoEvent, 26 | addr platform.Paddr) error { 27 | 28 | if handler != nil { 29 | 30 | // Our offset from handler start. 31 | offset := addr.OffsetFrom(handler.start) 32 | 33 | // Submit our function. 34 | err := handler.queue.Submit(ioevent, offset) 35 | 36 | // Should we save this request? 37 | if ioevent.IsWrite() && err == SaveIO { 38 | err = cache.save( 39 | vm, 40 | addr, 41 | handler, 42 | ioevent, 43 | offset) 44 | } 45 | 46 | // Return to our vcpu. 47 | return err 48 | 49 | } else if !ioevent.IsWrite() { 50 | 51 | // Invalid reads return all 1's. 52 | switch ioevent.Size() { 53 | case 1: 54 | ioevent.SetData(0xff) 55 | case 2: 56 | ioevent.SetData(0xffff) 57 | case 4: 58 | ioevent.SetData(0xffffffff) 59 | case 8: 60 | ioevent.SetData(0xffffffffffffffff) 61 | } 62 | } 63 | 64 | return nil 65 | } 66 | 67 | func (model *Model) HandlePio( 68 | vm *platform.Vm, 69 | event *platform.ExitPio) error { 70 | 71 | handler := model.pio_cache.lookup(event.Port()) 72 | ioevent := &PioEvent{event} 73 | return model.Handle(vm, model.pio_cache, handler, ioevent, event.Port()) 74 | } 75 | 76 | func (model *Model) HandleMmio( 77 | vm *platform.Vm, 78 | event *platform.ExitMmio) error { 79 | 80 | handler := model.mmio_cache.lookup(event.Addr()) 81 | ioevent := &MmioEvent{event} 82 | return model.Handle(vm, model.mmio_cache, handler, ioevent, event.Addr()) 83 | } 84 | -------------------------------------------------------------------------------- /src/novmm/machine/errors.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package machine 16 | 17 | import ( 18 | "errors" 19 | "fmt" 20 | ) 21 | 22 | // Basic errors. 23 | var DeviceAlreadyPaused = errors.New("Device already paused!") 24 | var DeviceNotPaused = errors.New("Device not paused!") 25 | 26 | // Memory allocation / layout errors. 27 | var MemoryConflict = errors.New("Memory regions conflict!") 28 | var MemoryNotFound = errors.New("Memory region not found!") 29 | var MemoryBusy = errors.New("Memory could not be allocated!") 30 | var MemoryUnaligned = errors.New("Memory not aligned!") 31 | var UserMemoryNotFound = errors.New("No user memory found?") 32 | 33 | // Interrupt allocation errors. 34 | var InterruptConflict = errors.New("Device interrupt conflict!") 35 | var InterruptUnavailable = errors.New("No interrupt available!") 36 | 37 | // PCI errors. 38 | var PciInvalidAddress = errors.New("Invalid PCI address!") 39 | var PciBusNotFound = errors.New("Requested PCI devices, but no bus found?") 40 | var PciMSIError = errors.New("MSI internal error?") 41 | var PciCapabilityMismatch = errors.New("Capability mismatch!") 42 | 43 | // UART errors. 44 | var UartUnknown = errors.New("Unknown COM port.") 45 | 46 | // Driver errors. 47 | func DriverUnknown(name string) error { 48 | return errors.New(fmt.Sprintf("Unknown driver: %s", name)) 49 | } 50 | 51 | // Virtio errors. 52 | var VirtioInvalidQueueSize = errors.New("Invalid VirtIO queue size!") 53 | var VirtioUnsupportedVnetHeader = errors.New("Unsupported vnet header size.") 54 | 55 | // I/O memoize errors. 56 | // This is an internal-only error which is returned from 57 | // a write handler. When this is returned (and the cache 58 | // has had a significant number of hits at that address) 59 | // we will create an eventfd for that particular address 60 | // and value. This will reduce the number of kernel-user 61 | // switches necessary to handle that particular address. 62 | var SaveIO = errors.New("Save I/O request (internal error).") 63 | -------------------------------------------------------------------------------- /src/novmm/machine/eventfd.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package machine 16 | 17 | import ( 18 | "novmm/platform" 19 | ) 20 | 21 | type WriteIoEvent struct { 22 | size uint 23 | data uint64 24 | } 25 | 26 | func (event *WriteIoEvent) Size() uint { 27 | return event.size 28 | } 29 | 30 | func (event *WriteIoEvent) GetData() uint64 { 31 | return event.data 32 | } 33 | 34 | func (event *WriteIoEvent) SetData(val uint64) { 35 | // This really shouldn't happen. 36 | // Perhaps we should consider recording 37 | // this and raising an error later? 38 | } 39 | 40 | func (event *WriteIoEvent) IsWrite() bool { 41 | return true 42 | } 43 | 44 | func (cache *IoCache) save( 45 | vm *platform.Vm, 46 | addr platform.Paddr, 47 | handler *IoHandler, 48 | ioevent IoEvent, 49 | offset uint64) error { 50 | 51 | // Do we have sufficient hits? 52 | if cache.hits[addr] < 100 { 53 | return nil 54 | } 55 | 56 | // Bind an eventfd. 57 | // Note that we pass in the exactly address here, 58 | // not the address associated with the IOHandler. 59 | boundfd, err := vm.NewBoundEventFd( 60 | addr, 61 | ioevent.Size(), 62 | cache.is_pio, 63 | true, 64 | ioevent.GetData()) 65 | if err != nil || boundfd == nil { 66 | return err 67 | } 68 | 69 | // Create a fake event. 70 | // This is because the real event will actually 71 | // reach into the vcpu registers to get the data. 72 | fake_event := &WriteIoEvent{ioevent.Size(), ioevent.GetData()} 73 | 74 | // Run our function. 75 | go func(ioevent IoEvent) { 76 | 77 | for { 78 | // Wait for the next event. 79 | _, err := boundfd.Wait() 80 | if err != nil { 81 | break 82 | } 83 | 84 | // Call our function. 85 | // We keep handling this device the same 86 | // way until it tells us to stop by returning 87 | // anything other than the SaveIO error. 88 | err = handler.queue.Submit(ioevent, offset) 89 | if err != SaveIO { 90 | break 91 | } 92 | } 93 | 94 | // Finished with the eventfd. 95 | boundfd.Close() 96 | 97 | }(fake_event) 98 | 99 | // Success. 100 | return nil 101 | } 102 | -------------------------------------------------------------------------------- /src/novmm/machine/interrupt.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package machine 16 | 17 | import ( 18 | "novmm/platform" 19 | ) 20 | 21 | // 22 | // InterruptMap -- 23 | // 24 | // Interrupts are much simpler than our 25 | // memory layout. We simply store a map 26 | // of allocated interrupts with a pointer 27 | // to the device info. 28 | 29 | type InterruptMap map[platform.Irq]Device 30 | -------------------------------------------------------------------------------- /src/novmm/machine/mmio.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package machine 16 | 17 | import ( 18 | "novmm/platform" 19 | ) 20 | 21 | type MmioEvent struct { 22 | *platform.ExitMmio 23 | } 24 | 25 | func (mmio MmioEvent) Size() uint { 26 | return mmio.ExitMmio.Length() 27 | } 28 | 29 | func (mmio MmioEvent) GetData() uint64 { 30 | return *mmio.ExitMmio.Data() 31 | } 32 | 33 | func (mmio MmioEvent) SetData(val uint64) { 34 | *mmio.ExitMmio.Data() = val 35 | } 36 | 37 | func (mmio MmioEvent) IsWrite() bool { 38 | return mmio.ExitMmio.IsWrite() 39 | } 40 | 41 | type MmioDevice struct { 42 | BaseDevice 43 | 44 | // A map of our available I/O. 45 | IoMap `json:"-"` 46 | IoHandlers `json:"-"` 47 | 48 | // Our address in memory. 49 | Offset platform.Paddr `json:"address"` 50 | 51 | // Our assigned interrupt. 52 | InterruptNumber platform.Irq `json:"interrupt"` 53 | 54 | // Regions that should be reserved. 55 | // NOTE: These have the offset applied. 56 | reservations []MemoryRegion `json:"-"` 57 | } 58 | 59 | func (mmio *MmioDevice) MmioHandlers() IoHandlers { 60 | return mmio.IoHandlers 61 | } 62 | 63 | func (mmio *MmioDevice) Attach(vm *platform.Vm, model *Model) error { 64 | 65 | // Build our IO Handlers. 66 | mmio.IoHandlers = make(IoHandlers) 67 | for region, ops := range mmio.IoMap { 68 | new_region := MemoryRegion{region.Start + mmio.Offset, region.Size} 69 | mmio.IoHandlers[new_region] = NewIoHandler(mmio, new_region.Start, ops) 70 | } 71 | 72 | // Reserve memory regions. 73 | if mmio.reservations != nil { 74 | for _, region := range mmio.reservations { 75 | err := model.Reserve( 76 | vm, 77 | mmio, 78 | MemoryTypeReserved, 79 | region.Start+mmio.Offset, 80 | region.Size, 81 | nil) 82 | if err != nil { 83 | return err 84 | } 85 | } 86 | } 87 | 88 | if mmio.InterruptNumber != 0 { 89 | // Reserve our interrupt. 90 | _, ok := model.InterruptMap[mmio.InterruptNumber] 91 | if ok { 92 | // Already a device there. 93 | return InterruptConflict 94 | } 95 | model.InterruptMap[mmio.InterruptNumber] = mmio 96 | 97 | } else { 98 | // Find an interrupt. 99 | for irq := platform.Irq(16); ; irq += 1 { 100 | if _, ok := model.InterruptMap[irq]; !ok { 101 | model.InterruptMap[irq] = mmio 102 | mmio.InterruptNumber = irq 103 | } 104 | } 105 | } 106 | 107 | return mmio.BaseDevice.Attach(vm, model) 108 | } 109 | -------------------------------------------------------------------------------- /src/novmm/machine/pcihost.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package machine 16 | 17 | // 18 | // PciHostBridge -- 19 | // 20 | // This is an example of PCI-to-PCI bridge. 21 | // It's not particularly well though-out, or sensible. 22 | // We'd probably want to chain a second PCI bus device 23 | // behind it somehow. 24 | // 25 | // As it stands, we're not going to use this bridge. 26 | // AFAIK the reason the CPU doesn't access all PCI devices 27 | // directly is because there is an electrical limit on 28 | // building PCI buses with too many devices. But this is 29 | // a VMM, so we don't have any electrical limits. :) 30 | // 31 | 32 | const ( 33 | PciCapabilityPortRoot = 0x40 34 | ) 35 | 36 | func NewPciHostBridge(info *DeviceInfo) (Device, error) { 37 | 38 | // Create a bus device. 39 | hostbridge, err := NewPciDevice( 40 | info, 41 | PciVendorId(0x1022), // AMD. 42 | PciDeviceId(0x7432), // Made-up. 43 | PciClassBridge, 44 | PciRevision(0), 45 | 0, 46 | 0) 47 | if err != nil { 48 | return nil, err 49 | } 50 | 51 | // A bridge only has 2 bars. 52 | hostbridge.PciBarCount = 2 53 | 54 | // Set our type & command. 55 | hostbridge.Config.Set8(0xe, 1) 56 | hostbridge.Config.Set8(0x4, hostbridge.Config.Get8(0x4)|0x04) 57 | 58 | // Add our PortRoot capability. 59 | hostbridge.Capabilities[PciCapabilityPortRoot] = &PciCapability{ 60 | Size: 0, 61 | } 62 | 63 | // Done. 64 | return hostbridge, nil 65 | } 66 | -------------------------------------------------------------------------------- /src/novmm/machine/pio.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package machine 16 | 17 | import ( 18 | "novmm/platform" 19 | ) 20 | 21 | type PioEvent struct { 22 | *platform.ExitPio 23 | } 24 | 25 | func (pio PioEvent) Size() uint { 26 | return pio.ExitPio.Size() 27 | } 28 | 29 | func (pio PioEvent) GetData() uint64 { 30 | return *pio.ExitPio.Data() 31 | } 32 | 33 | func (pio PioEvent) SetData(val uint64) { 34 | *pio.ExitPio.Data() = val 35 | } 36 | 37 | func (pio PioEvent) IsWrite() bool { 38 | return pio.ExitPio.IsOut() 39 | } 40 | 41 | type PioDevice struct { 42 | BaseDevice 43 | 44 | // A map of our available ports. 45 | IoMap `json:"-"` 46 | IoHandlers `json:"-"` 47 | 48 | // Our address in memory. 49 | Offset platform.Paddr `json:"base"` 50 | } 51 | 52 | func (pio *PioDevice) PioHandlers() IoHandlers { 53 | return pio.IoHandlers 54 | } 55 | 56 | func (pio *PioDevice) Attach(vm *platform.Vm, model *Model) error { 57 | 58 | // Build our IO Handlers. 59 | pio.IoHandlers = make(IoHandlers) 60 | for region, ops := range pio.IoMap { 61 | new_region := MemoryRegion{region.Start + pio.Offset, region.Size} 62 | pio.IoHandlers[new_region] = NewIoHandler(pio, new_region.Start, ops) 63 | } 64 | 65 | // NOTE: Unlike pio devices, we don't reserve 66 | // memory regions for our ports. Whichever device 67 | // gets there first wins. 68 | 69 | return pio.BaseDevice.Attach(vm, model) 70 | } 71 | -------------------------------------------------------------------------------- /src/novmm/machine/pit.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package machine 16 | 17 | import ( 18 | "novmm/platform" 19 | ) 20 | 21 | type Pit struct { 22 | BaseDevice 23 | 24 | // Our pit state. 25 | // Similar to the pit, we consider the platform 26 | // PIT to be an intrinsic part of our "pit". 27 | Pit platform.PitState `json:"pit"` 28 | } 29 | 30 | func NewPit(info *DeviceInfo) (Device, error) { 31 | pit := new(Pit) 32 | return pit, pit.init(info) 33 | } 34 | 35 | func (pit *Pit) Attach(vm *platform.Vm, model *Model) error { 36 | 37 | // Create our PIT. 38 | err := vm.CreatePit() 39 | if err != nil { 40 | return err 41 | } 42 | 43 | // We're good. 44 | return nil 45 | } 46 | 47 | func (pit *Pit) Save(vm *platform.Vm) error { 48 | 49 | var err error 50 | 51 | // Save our Pit state. 52 | pit.Pit, err = vm.GetPit() 53 | if err != nil { 54 | return err 55 | } 56 | 57 | // We're good. 58 | return nil 59 | } 60 | 61 | func (pit *Pit) Load(vm *platform.Vm) error { 62 | // Load state. 63 | return vm.SetPit(pit.Pit) 64 | } 65 | -------------------------------------------------------------------------------- /src/novmm/machine/proxy.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package machine 16 | 17 | import ( 18 | "io" 19 | ) 20 | 21 | // 22 | // Proxy -- 23 | // 24 | // The proxy is something that allows us to connect 25 | // with the agent inside the VM. At the moment, this 26 | // is only the virtio_console device. Theoretically, 27 | // any of the devices could implement this interface 28 | // if the agent supported it.... 29 | // 30 | 31 | type Proxy interface { 32 | io.ReadWriteCloser 33 | } 34 | -------------------------------------------------------------------------------- /src/novmm/machine/ram.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package machine 16 | 17 | import ( 18 | "math" 19 | "unsafe" 20 | ) 21 | 22 | type Ram struct { 23 | Data []byte `json:"data"` 24 | } 25 | 26 | func (ram *Ram) Size() int { 27 | return len(ram.Data) 28 | } 29 | 30 | func (ram *Ram) GrowTo(size int) { 31 | if size > len(ram.Data) { 32 | missing := size - len(ram.Data) 33 | new_bytes := make([]byte, missing, missing) 34 | ram.Data = append(ram.Data, new_bytes...) 35 | } 36 | } 37 | 38 | func (ram *Ram) Set8(offset int, data uint8) { 39 | ram.Data[offset] = byte(data) 40 | } 41 | 42 | func (ram *Ram) Get8(offset int) uint8 { 43 | return ram.Data[offset] 44 | } 45 | 46 | func (ram *Ram) Set16(offset int, data uint16) { 47 | *(*uint16)(unsafe.Pointer(&ram.Data[offset])) = data 48 | } 49 | 50 | func (ram *Ram) Get16(offset int) uint16 { 51 | return *(*uint16)(unsafe.Pointer(&ram.Data[offset])) 52 | } 53 | 54 | func (ram *Ram) Set32(offset int, data uint32) { 55 | *(*uint32)(unsafe.Pointer(&ram.Data[offset])) = data 56 | } 57 | 58 | func (ram *Ram) Get32(offset int) uint32 { 59 | return *(*uint32)(unsafe.Pointer(&ram.Data[offset])) 60 | } 61 | 62 | func (ram *Ram) Set64(offset int, data uint64) { 63 | *(*uint64)(unsafe.Pointer(&ram.Data[offset])) = data 64 | } 65 | 66 | func (ram *Ram) Get64(offset int) uint64 { 67 | return *(*uint64)(unsafe.Pointer(&ram.Data[offset])) 68 | } 69 | 70 | func (ram *Ram) Read(offset uint64, size uint) (uint64, error) { 71 | 72 | value := uint64(math.MaxUint64) 73 | 74 | // Is it greater than our size? 75 | if offset+uint64(size) > uint64(ram.Size()) { 76 | // Ignore. 77 | return value, nil 78 | } 79 | 80 | // Handle default. 81 | switch size { 82 | case 1: 83 | value = uint64(ram.Get8(int(offset))) 84 | case 2: 85 | value = uint64(ram.Get16(int(offset))) 86 | case 4: 87 | value = uint64(ram.Get32(int(offset))) 88 | case 8: 89 | value = ram.Get64(int(offset)) 90 | } 91 | 92 | return value, nil 93 | } 94 | 95 | func (ram *Ram) Write(offset uint64, size uint, value uint64) error { 96 | 97 | // Is it greater than our size? 98 | if offset+uint64(size) > uint64(ram.Size()) { 99 | // Ignore. 100 | return nil 101 | } 102 | 103 | // Handle default. 104 | switch size { 105 | case 1: 106 | ram.Set8(int(offset), uint8(value)) 107 | case 2: 108 | ram.Set16(int(offset), uint16(value)) 109 | case 4: 110 | ram.Set32(int(offset), uint32(value)) 111 | case 8: 112 | ram.Set64(int(offset), value) 113 | } 114 | 115 | return nil 116 | } 117 | 118 | func NewRam(size int) *Ram { 119 | ram := new(Ram) 120 | ram.Data = make([]byte, size, size) 121 | return ram 122 | } 123 | -------------------------------------------------------------------------------- /src/novmm/machine/register.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package machine 16 | 17 | import ( 18 | "math" 19 | ) 20 | 21 | type Register struct { 22 | // The value of the register. 23 | Value uint64 `json:"value"` 24 | 25 | // Read-only bits? 26 | readonly uint64 27 | 28 | // Clear these bits on read. 29 | readclr uint64 30 | } 31 | 32 | func (register *Register) Read(offset uint64, size uint) (uint64, error) { 33 | var mask uint64 34 | 35 | switch size { 36 | case 1: 37 | mask = 0x00000000000000ff 38 | case 2: 39 | mask = 0x000000000000ffff 40 | case 4: 41 | mask = 0x00000000ffffffff 42 | case 8: 43 | mask = 0xffffffffffffffff 44 | } 45 | 46 | value := uint64(math.MaxUint64) 47 | 48 | switch offset { 49 | case 0: 50 | value = (register.Value) & mask 51 | case 1: 52 | value = (register.Value >> 8) & mask 53 | mask = mask << 8 54 | case 2: 55 | value = (register.Value >> 16) & mask 56 | mask = mask << 16 57 | case 3: 58 | value = (register.Value >> 24) & mask 59 | mask = mask << 24 60 | case 4: 61 | value = (register.Value >> 32) & mask 62 | mask = mask << 32 63 | case 5: 64 | value = (register.Value >> 40) & mask 65 | mask = mask << 40 66 | case 6: 67 | value = (register.Value >> 48) & mask 68 | mask = mask << 48 69 | case 7: 70 | value = (register.Value >> 56) & mask 71 | mask = mask << 56 72 | } 73 | 74 | register.Value = register.Value & ^(mask & register.readclr) 75 | return value, nil 76 | } 77 | 78 | func (register *Register) Write(offset uint64, size uint, value uint64) error { 79 | var mask uint64 80 | 81 | switch size { 82 | case 1: 83 | mask = 0x00000000000000ff & ^register.readonly 84 | case 2: 85 | mask = 0x000000000000ffff & ^register.readonly 86 | case 4: 87 | mask = 0x00000000ffffffff & ^register.readonly 88 | case 8: 89 | mask = 0xffffffffffffffff & ^register.readonly 90 | } 91 | 92 | value = value & mask 93 | 94 | switch offset { 95 | case 1: 96 | mask = mask << 8 97 | value = value << 8 98 | case 2: 99 | mask = mask << 16 100 | value = value << 16 101 | case 3: 102 | mask = mask << 24 103 | value = value << 24 104 | case 4: 105 | mask = mask << 32 106 | value = value << 32 107 | case 5: 108 | mask = mask << 40 109 | value = value << 40 110 | case 6: 111 | mask = mask << 48 112 | value = value << 48 113 | case 7: 114 | mask = mask << 56 115 | value = value << 56 116 | } 117 | 118 | register.Value = (register.Value & ^mask) | (value & mask) 119 | return nil 120 | } 121 | -------------------------------------------------------------------------------- /src/novmm/machine/state.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package machine 16 | 17 | import ( 18 | "bytes" 19 | "log" 20 | "novmm/platform" 21 | "novmm/utils" 22 | ) 23 | 24 | type DeviceInfo struct { 25 | // Friendly name. 26 | Name string `json:"name"` 27 | 28 | // Driver name. 29 | Driver string `json:"driver"` 30 | 31 | // Device-specific info. 32 | Data interface{} `json:"data"` 33 | 34 | // Debugging? 35 | Debug bool `json:"debug"` 36 | } 37 | 38 | func (info DeviceInfo) Load() (Device, error) { 39 | 40 | // Find the appropriate driver. 41 | driver, ok := drivers[info.Driver] 42 | if !ok { 43 | return nil, DriverUnknown(info.Driver) 44 | } 45 | 46 | // Load the driver. 47 | device, err := driver(&info) 48 | if err != nil { 49 | return nil, err 50 | } 51 | 52 | if info.Data != nil { 53 | // Scratch data. 54 | buffer := bytes.NewBuffer(nil) 55 | 56 | // Encode the original object. 57 | encoder := utils.NewEncoder(buffer) 58 | err = encoder.Encode(info.Data) 59 | if err != nil { 60 | return nil, err 61 | } 62 | 63 | // Decode a new object. 64 | // This will override all the default 65 | // settings in the initialized object. 66 | decoder := utils.NewDecoder(buffer) 67 | log.Printf("Loading %s...", device.Name()) 68 | err = decoder.Decode(device) 69 | if err != nil { 70 | return nil, err 71 | } 72 | } 73 | 74 | // Save the original device. 75 | // This will allow us to implement a 76 | // simple Save() method that serializes 77 | // the state of this device as it exists. 78 | info.Data = device 79 | 80 | // We're done. 81 | return device, nil 82 | } 83 | 84 | func (model *Model) CreateDevices( 85 | vm *platform.Vm, 86 | spec []DeviceInfo, 87 | debug bool) (Proxy, error) { 88 | 89 | // The first proxy decoded. 90 | var proxy Proxy 91 | 92 | // Load all devices. 93 | for _, info := range spec { 94 | device, err := info.Load() 95 | if err != nil { 96 | return nil, err 97 | } 98 | 99 | if debug { 100 | // Set our debug param. 101 | device.SetDebugging(debug) 102 | } 103 | 104 | // Try the attach. 105 | err = device.Attach(vm, model) 106 | if err != nil { 107 | return nil, err 108 | } 109 | 110 | // Add the device to our list. 111 | model.devices = append(model.devices, device) 112 | 113 | // Is this a proxy? 114 | if proxy == nil { 115 | proxy, _ = device.(Proxy) 116 | } 117 | } 118 | 119 | // Flush the model cache. 120 | return proxy, model.flush() 121 | } 122 | 123 | func NewDeviceInfo(device Device) (DeviceInfo, error) { 124 | 125 | return DeviceInfo{ 126 | Name: device.Name(), 127 | Driver: device.Driver(), 128 | Data: device, 129 | Debug: device.IsDebugging(), 130 | }, nil 131 | } 132 | -------------------------------------------------------------------------------- /src/novmm/machine/virtio.c: -------------------------------------------------------------------------------- 1 | /* 2 | * virtio.c 3 | * 4 | * Copyright 2014 Google Inc. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include "virtio.h" 20 | 21 | int vring_get_buf( 22 | struct vring* vring, 23 | __u16 consumed, 24 | __u16* flags, 25 | __u16* index, 26 | __u16* used_event) { 27 | 28 | if (consumed != vring->avail->idx) { 29 | 30 | if (consumed+1 < vring->avail->idx) { 31 | vring->used->flags = VRING_USED_F_NO_NOTIFY; 32 | } else { 33 | vring->used->flags = 0; 34 | vring_avail_event(vring) = consumed+1; 35 | } 36 | 37 | *flags = vring->avail->flags; 38 | *index = vring->avail->ring[consumed%vring->num]; 39 | 40 | return 1; 41 | } 42 | 43 | return 0; 44 | } 45 | 46 | void vring_read_desc( 47 | struct vring_desc* desc, 48 | __u64* addr, 49 | __u32* len, 50 | __u16* flags, 51 | __u16* next) { 52 | 53 | *addr = desc->addr; 54 | *len = desc->len; 55 | *flags = desc->flags; 56 | *next = desc->next; 57 | } 58 | 59 | void vring_get_index( 60 | struct vring* vring, 61 | __u16 index, 62 | __u64* addr, 63 | __u32* len, 64 | __u16* flags, 65 | __u16* next) { 66 | 67 | vring_read_desc(&vring->desc[index], addr, len, flags, next); 68 | } 69 | 70 | void vring_put_buf( 71 | struct vring* vring, 72 | __u16 index, 73 | __u32 len, 74 | int* evt_interrupt, 75 | int* no_interrupt) { 76 | 77 | vring->used->ring[vring->used->idx%vring->num].id = index; 78 | vring->used->ring[vring->used->idx%vring->num].len = len; 79 | *evt_interrupt = vring_used_event(vring) == vring->used->idx; 80 | *no_interrupt = vring->used->flags & VRING_AVAIL_F_NO_INTERRUPT; 81 | 82 | asm volatile ("" : : : "memory"); 83 | vring->used->idx += 1; 84 | asm volatile ("" : : : "memory"); 85 | } 86 | -------------------------------------------------------------------------------- /src/novmm/machine/virtio.h: -------------------------------------------------------------------------------- 1 | /* 2 | * virtio.h 3 | * 4 | * Copyright 2014 Google Inc. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include 20 | 21 | int vring_get_buf( 22 | struct vring* vring, 23 | __u16 consumed, 24 | __u16* flags, 25 | __u16* index, 26 | __u16* used_event); 27 | 28 | void vring_read_desc( 29 | struct vring_desc* desc, 30 | __u64* addr, 31 | __u32* len, 32 | __u16* flags, 33 | __u16* next); 34 | 35 | void vring_get_index( 36 | struct vring* vring, 37 | __u16 index, 38 | __u64* addr, 39 | __u32* len, 40 | __u16* flags, 41 | __u16* next); 42 | 43 | void vring_put_buf( 44 | struct vring* vring, 45 | __u16 index, 46 | __u32 len, 47 | int* evt_interrupt, 48 | int* no_interrupt); 49 | -------------------------------------------------------------------------------- /src/novmm/machine/virtio_buffer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * virtio_buffer.c 3 | * 4 | * Copyright 2014 Google Inc. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include 20 | #include 21 | #include "virtio_buffer.h" 22 | 23 | int do_iovec( 24 | int fd, 25 | int count, 26 | void** ptrs, 27 | int* sizes, 28 | off_t offset, 29 | int write) { 30 | 31 | int vecno; 32 | struct iovec vec[count]; 33 | size_t rval = 0; 34 | 35 | for (vecno = 0; vecno < count; vecno += 1) { 36 | vec[vecno].iov_base = (char*)ptrs[vecno]; 37 | vec[vecno].iov_len = sizes[vecno]; 38 | } 39 | 40 | if (offset != (off_t)-1) { 41 | if (write) { 42 | rval = pwritev(fd, &vec[0], count, offset); 43 | } else { 44 | rval = preadv(fd, &vec[0], count, offset); 45 | } 46 | } else { 47 | if (write) { 48 | rval = writev(fd, &vec[0], count); 49 | } else { 50 | rval = readv(fd, &vec[0], count); 51 | } 52 | } 53 | 54 | if (rval < 0) { 55 | return -errno; 56 | } 57 | 58 | return rval; 59 | } 60 | -------------------------------------------------------------------------------- /src/novmm/machine/virtio_buffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * virtio_buffer.h 3 | * 4 | * Copyright 2014 Google Inc. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include 20 | 21 | int do_iovec( 22 | int fd, 23 | int count, 24 | void** ptrs, 25 | int* sizes, 26 | off_t offset, 27 | int write); 28 | -------------------------------------------------------------------------------- /src/novmm/machine/virtio_fs.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package machine 16 | 17 | import ( 18 | "log" 19 | "novmm/plan9" 20 | "novmm/platform" 21 | ) 22 | 23 | const ( 24 | VirtioFsFMount = 1 25 | ) 26 | 27 | type VirtioFsDevice struct { 28 | *VirtioDevice 29 | 30 | // Our filesystem tag. 31 | Tag string `json:"tag"` 32 | 33 | // Debug fs operations? 34 | Debugfs bool `json:"debugfs"` 35 | 36 | // Our plan9 server. 37 | plan9.Fs 38 | } 39 | 40 | func (fs *VirtioFsDevice) process(buf *VirtioBuffer) { 41 | 42 | // Map our request & response. 43 | // 44 | // NOTE: The way these segments are handled on the wire 45 | // is pretty odd, in my opinion. We don't touch the original 46 | // request, but instead append the response to the *next* 47 | // segment in the list. For "zero-copy" requests (i.e. read), 48 | // Linux may chain a request segment, data segment, then a 49 | // response segment. We don't do any looking at the segments 50 | // here, but rather use the generic Stream() with appropriate 51 | // offsets. These should map directly and efficiently onto 52 | // the logical segments, but will handle cases where they 53 | // don't (for whatever reason). 54 | // 55 | // This requires us to peek into the first two bytes of the 56 | // 9P message and pull out the length. This is the only very 57 | // 9P-specific code that exists in this module. 58 | 59 | req := NewVirtioStream(buf, 0) 60 | length := req.Read16() 61 | req.ReadRewind() 62 | resp := NewVirtioStream(buf, int(length)) 63 | 64 | // Handle our request. 65 | err := fs.Fs.Handle(req, resp, fs.Debugfs) 66 | if err != nil { 67 | log.Printf("FS error: %s", err.Error()) 68 | } 69 | 70 | // Finished request. 71 | fs.VirtioDevice.Channels[0].outgoing <- buf 72 | } 73 | 74 | func (fs *VirtioFsDevice) run() error { 75 | 76 | for { 77 | // Read a request. 78 | req := <-fs.VirtioDevice.Channels[0].incoming 79 | 80 | // Process it. 81 | go fs.process(req) 82 | } 83 | 84 | return nil 85 | } 86 | 87 | func setupFs(device *VirtioDevice) (Device, error) { 88 | 89 | // Create our channel (requests). 90 | device.Channels[0] = NewVirtioChannel(0, 512) 91 | device.Channels[1] = NewVirtioChannel(1, 512) 92 | 93 | // Initialize our FS. 94 | fs := new(VirtioFsDevice) 95 | fs.VirtioDevice = device 96 | fs.Tag = "default" 97 | 98 | return fs, fs.Init() 99 | } 100 | 101 | func NewVirtioMmioFs(info *DeviceInfo) (Device, error) { 102 | device, err := NewMmioVirtioDevice(info, VirtioType9p) 103 | if err != nil { 104 | return nil, err 105 | } 106 | 107 | return setupFs(device) 108 | } 109 | 110 | func NewVirtioPciFs(info *DeviceInfo) (Device, error) { 111 | device, err := NewPciVirtioDevice(info, PciClassMisc, VirtioType9p, 16) 112 | if err != nil { 113 | return nil, err 114 | } 115 | 116 | return setupFs(device) 117 | } 118 | 119 | func (fs *VirtioFsDevice) Attach(vm *platform.Vm, model *Model) error { 120 | err := fs.VirtioDevice.Attach(vm, model) 121 | if err != nil { 122 | return err 123 | } 124 | 125 | // This feature is not optional. 126 | // We ignore serialized features. 127 | fs.SetFeatures(VirtioFsFMount) 128 | 129 | // Make sure the config reflects our tag. 130 | tag_bytes := []byte(fs.Tag) 131 | fs.Config.GrowTo(2 + len(tag_bytes) + 1) 132 | fs.Config.Set16(0, uint16(len(tag_bytes))) 133 | for i := 0; i < len(tag_bytes); i += 1 { 134 | fs.Config.Set8(2+i, uint8(tag_bytes[i])) 135 | } 136 | 137 | // Ensure the file system is sane. 138 | err = fs.Fs.Attach() 139 | if err != nil { 140 | return err 141 | } 142 | 143 | // Start our backend process. 144 | go fs.run() 145 | 146 | return nil 147 | } 148 | -------------------------------------------------------------------------------- /src/novmm/plan9/buffer.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package plan9 16 | 17 | type Buffer interface { 18 | ReadLeft() int 19 | WriteLeft() int 20 | 21 | ReadRewind() 22 | WriteRewind() 23 | 24 | Read8() uint8 25 | Read16() uint16 26 | Read32() uint32 27 | Read64() uint64 28 | ReadBytes(length int) []byte 29 | ReadString() string 30 | 31 | Write8(value uint8) 32 | Write16(value uint16) 33 | Write32(value uint32) 34 | Write64(value uint64) 35 | WriteBytes(value []byte) 36 | WriteString(value string) 37 | 38 | ReadFromFd(fd int, offset int64, length int) (int, error) 39 | WriteToFd(fd int, offset int64, length int) (int, error) 40 | } 41 | 42 | func gqid(buf Buffer, qid *Qid) { 43 | qid.Type = buf.Read8() 44 | qid.Version = buf.Read32() 45 | qid.Path = buf.Read64() 46 | } 47 | 48 | func gstat(buf Buffer, d *Dir, dotu bool) { 49 | buf.Read16() // Read length. 50 | d.Type = buf.Read16() 51 | d.Dev = buf.Read32() 52 | gqid(buf, &d.Qid) 53 | d.Mode = buf.Read32() 54 | d.Atime = buf.Read32() 55 | d.Mtime = buf.Read32() 56 | d.Length = buf.Read64() 57 | d.Name = buf.ReadString() 58 | d.Uid = buf.ReadString() 59 | d.Gid = buf.ReadString() 60 | d.Muid = buf.ReadString() 61 | if dotu { 62 | d.Ext = buf.ReadString() 63 | d.Uidnum = buf.Read32() 64 | d.Gidnum = buf.Read32() 65 | d.Muidnum = buf.Read32() 66 | } else { 67 | d.Uidnum = NOUID 68 | d.Gidnum = NOUID 69 | d.Muidnum = NOUID 70 | } 71 | } 72 | 73 | func statsz(d *Dir, dotu bool) int { 74 | sz := 2 + 2 + 4 + 13 + 4 + 4 + 4 + 8 + 2 + 2 + 2 + 2 + 75 | len(d.Name) + len(d.Uid) + len(d.Gid) + len(d.Muid) 76 | if dotu { 77 | sz += 2 + 4 + 4 + 4 + len(d.Ext) 78 | } 79 | 80 | return sz 81 | } 82 | 83 | func pqid(buf Buffer, qid *Qid) { 84 | buf.Write8(qid.Type) 85 | buf.Write32(qid.Version) 86 | buf.Write64(qid.Path) 87 | } 88 | 89 | func pstat(buf Buffer, d *Dir, dotu bool) int { 90 | sz := statsz(d, dotu) 91 | buf.Write16(uint16(sz - 2)) 92 | buf.Write16(d.Type) 93 | buf.Write32(d.Dev) 94 | pqid(buf, &d.Qid) 95 | buf.Write32(d.Mode) 96 | buf.Write32(d.Atime) 97 | buf.Write32(d.Mtime) 98 | buf.Write64(d.Length) 99 | buf.WriteString(d.Name) 100 | buf.WriteString(d.Uid) 101 | buf.WriteString(d.Gid) 102 | buf.WriteString(d.Muid) 103 | if dotu { 104 | buf.WriteString(d.Ext) 105 | buf.Write32(d.Uidnum) 106 | buf.Write32(d.Gidnum) 107 | buf.Write32(d.Muidnum) 108 | } 109 | return sz 110 | } 111 | -------------------------------------------------------------------------------- /src/novmm/plan9/errors.go: -------------------------------------------------------------------------------- 1 | // Original file Copyright 2009 The Go9p Authors. All rights reserved. 2 | // Full license available in licenses/go9p. 3 | // 4 | // Modifications Copyright 2014 Google Inc. All rights reserved. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package plan9 19 | 20 | import ( 21 | "errors" 22 | ) 23 | 24 | // Global errors. 25 | var BufferInsufficient = errors.New("insufficient buffer?") 26 | var InvalidMessage = errors.New("invalid 9pfs message?") 27 | var XattrError = errors.New("unable to fetch xattr?") 28 | 29 | // Internal errors. 30 | var Eunknownfid error = &Error{"unknown fid", EINVAL} 31 | var Enoauth error = &Error{"no authentication required", EINVAL} 32 | var Einuse error = &Error{"fid already in use", EINVAL} 33 | var Ebaduse error = &Error{"bad use of fid", EINVAL} 34 | var Eopen error = &Error{"fid already opened", EINVAL} 35 | var Enotdir error = &Error{"not a directory", ENOTDIR} 36 | var Eperm error = &Error{"permission denied", EPERM} 37 | var Etoolarge error = &Error{"i/o count too large", EINVAL} 38 | var Ebadoffset error = &Error{"bad offset in directory read", EINVAL} 39 | var Edirchange error = &Error{"cannot convert between files and directories", EINVAL} 40 | var Enouser error = &Error{"unknown user", EINVAL} 41 | var Enotimpl error = &Error{"not implemented", EINVAL} 42 | var Eexist = &Error{"file already exists", EEXIST} 43 | var Enoent = &Error{"file not found", ENOENT} 44 | var Enotempty = &Error{"directory not empty", EPERM} 45 | -------------------------------------------------------------------------------- /src/novmm/plan9/fid.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package plan9 16 | 17 | import ( 18 | "encoding/json" 19 | "sync/atomic" 20 | ) 21 | 22 | type Fid struct { 23 | // The associated Fid. 24 | Fid uint32 `json:"fid"` 25 | 26 | // Runtime references. 27 | refs int32 `json:"-"` 28 | 29 | // The associated path. 30 | Path string `json:"path"` 31 | 32 | // True if the Fid is opened. 33 | Opened bool `json:"opened"` 34 | 35 | // Open mode (O* flags). 36 | Omode uint8 `json:"omode"` 37 | 38 | // If directory, next valid read position. 39 | Diroffset uint64 `json:"diroffset"` 40 | 41 | // If directory, list of children (reset by read(offset=0). 42 | Direntries []*Dir `json:"direntries"` 43 | 44 | // The associated file. 45 | // 46 | // This is looked up from the filesystem map 47 | // when the new Fid is created. Note that multiple 48 | // Fids may refer to the same file object, and 49 | // they are refcounted separately. 50 | // 51 | // This is not serialized like the rest of the Fid. 52 | // When the Fs is loaded, the Init() method is called, 53 | // which will reinitialize all the File objects. 54 | file *File 55 | } 56 | 57 | // 58 | // Our collection of Fids. 59 | // 60 | // This is a special type to handle marshal/unmarshal. 61 | type Fidpool map[uint32]*Fid 62 | 63 | func (fs *Fs) GetFid(fidno uint32) *Fid { 64 | 65 | fs.fidLock.RLock() 66 | fid, present := fs.Pool[fidno] 67 | if present { 68 | atomic.AddInt32(&fid.refs, 1) 69 | } 70 | fs.fidLock.RUnlock() 71 | 72 | return fid 73 | } 74 | 75 | func (fs *Fs) NewFid( 76 | fidno uint32, 77 | path string, 78 | file *File) (*Fid, error) { 79 | 80 | fs.fidLock.Lock() 81 | _, present := fs.Pool[fidno] 82 | if present { 83 | fs.fidLock.Unlock() 84 | return nil, Einuse 85 | } 86 | 87 | fid := new(Fid) 88 | fid.Fid = fidno 89 | fid.refs = 1 90 | fid.Path = path 91 | fid.file = file 92 | 93 | fs.Pool[fidno] = fid 94 | fs.fidLock.Unlock() 95 | 96 | return fid, nil 97 | } 98 | 99 | func (fid *Fid) DecRef(fs *Fs) { 100 | 101 | new_refs := atomic.AddInt32(&fid.refs, -1) 102 | 103 | if new_refs == 0 { 104 | fs.fidLock.Lock() 105 | if fid.refs != 0 { 106 | // Race condition caught. 107 | fs.fidLock.Unlock() 108 | return 109 | } 110 | 111 | // Remove this fid. 112 | delete(fs.Pool, fid.Fid) 113 | fs.fidLock.Unlock() 114 | 115 | // Lose our file reference. 116 | fid.file.DecRef(fs, fid.Path) 117 | } 118 | } 119 | 120 | func (fidpool *Fidpool) MarshalJSON() ([]byte, error) { 121 | 122 | // Create an array. 123 | fids := make([]*Fid, 0, len(*fidpool)) 124 | for _, fid := range *fidpool { 125 | fids = append(fids, fid) 126 | } 127 | 128 | // Marshal as an array. 129 | return json.Marshal(fids) 130 | } 131 | 132 | func (fidpool *Fidpool) UnmarshalJSON(data []byte) error { 133 | 134 | // Unmarshal as an array. 135 | fids := make([]*Fid, 0, 0) 136 | err := json.Unmarshal(data, &fids) 137 | if err != nil { 138 | return err 139 | } 140 | 141 | // Load all elements. 142 | for _, fid := range fids { 143 | (*fidpool)[fid.Fid] = fid 144 | } 145 | 146 | return nil 147 | } 148 | -------------------------------------------------------------------------------- /src/novmm/plan9/xattr.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package plan9 16 | 17 | /* 18 | #include 19 | #include 20 | #include 21 | */ 22 | import "C" 23 | 24 | import ( 25 | "path" 26 | "syscall" 27 | "unsafe" 28 | ) 29 | 30 | func readdelattr(filepath string) (bool, error) { 31 | val := C.char(0) 32 | err := C.getxattr( 33 | C.CString(filepath), 34 | C.CString("novm-deleted"), 35 | unsafe.Pointer(&val), 36 | C.size_t(1)) 37 | if err != C.ssize_t(1) { 38 | var stat syscall.Stat_t 39 | err := syscall.Stat( 40 | path.Join(filepath, ".deleted"), 41 | &stat) 42 | if err != nil { 43 | return false, err 44 | } 45 | return true, nil 46 | } 47 | return val == C.char(1), nil 48 | } 49 | 50 | func setdelattr(filepath string) error { 51 | val := C.char(1) 52 | e := C.setxattr( 53 | C.CString(filepath), 54 | C.CString("novm-deleted"), 55 | unsafe.Pointer(&val), 56 | C.size_t(1), 57 | C.int(0)) 58 | if e != 0 { 59 | fd, err := syscall.Open( 60 | path.Join(filepath, ".deleted"), 61 | syscall.O_RDWR|syscall.O_CREAT, 62 | syscall.S_IRUSR|syscall.S_IWUSR|syscall.S_IXUSR) 63 | if err == nil { 64 | syscall.Close(fd) 65 | } 66 | return err 67 | } 68 | return nil 69 | } 70 | 71 | func cleardelattr(filepath string) error { 72 | val := C.char(0) 73 | e := C.setxattr( 74 | C.CString(filepath), 75 | C.CString("novm-deleted"), 76 | unsafe.Pointer(&val), 77 | C.size_t(1), 78 | C.int(0)) 79 | if e != 0 { 80 | return syscall.Unlink(path.Join(filepath, ".deleted")) 81 | } 82 | return nil 83 | } 84 | -------------------------------------------------------------------------------- /src/novmm/platform/errors.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package platform 16 | 17 | import ( 18 | "errors" 19 | ) 20 | 21 | // Serialization. 22 | var VcpuIncompatible = errors.New("Incompatible VCPU data?") 23 | var PitIncompatible = errors.New("Incompatible PIT state?") 24 | var IrqChipIncompatible = errors.New("Incompatible IRQ chip state?") 25 | var LApicIncompatible = errors.New("Incompatible LApic state?") 26 | 27 | // Register errors. 28 | var UnknownRegister = errors.New("Unknown Register") 29 | 30 | // Vcpu state errors. 31 | var NotPaused = errors.New("Vcpu is not paused?") 32 | var AlreadyPaused = errors.New("Vcpu is already paused.") 33 | var UnknownState = errors.New("Unknown vcpu state?") 34 | -------------------------------------------------------------------------------- /src/novmm/platform/eventfd_linux.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // +build linux 16 | package platform 17 | 18 | /* 19 | #include 20 | 21 | const int EfdCloExec = EFD_CLOEXEC; 22 | */ 23 | import "C" 24 | 25 | import ( 26 | "syscall" 27 | "unsafe" 28 | ) 29 | 30 | // Event server. 31 | // 32 | // This file was created in the hopes that I would 33 | // be able to bolt on an event server to the internal 34 | // network hub. Not so simple. That's all in the net 35 | // namespace, and very much network-specific. 36 | // 37 | // So... for now, this will just use blocking system 38 | // calls. It's relatively lightweight and we're not scaling 39 | // to thousands of concurrent goroutines, just dozens. 40 | // 41 | // In the future, this is a great opportunity to improve 42 | // the core archiecture (and eliminate a few system threads). 43 | 44 | type EventFd struct { 45 | // Underlying FD. 46 | // NOTE: In reality we may want to serialize read/write 47 | // access to this fd as I'm fairly sure we will end up 48 | // with unexpected errors if this interface is used in 49 | // this way. However, we'll keep this as a simple runtime 50 | // adaptor and punt that complexity up to the next level. 51 | fd int 52 | } 53 | 54 | func NewEventFd() (*EventFd, error) { 55 | // Create new eventfd. 56 | // NOTE: It's critical that it's non-blocking for the hub 57 | // integration below (otherwise it'll just end up blocking 58 | // in the Read() or Write() system call. 59 | // But given that we aren't using the hub, for now this is 60 | // just a regular blocking call. C'est la vie. 61 | fd, _, e := syscall.Syscall( 62 | syscall.SYS_EVENTFD, 63 | 0, 64 | uintptr(C.EfdCloExec), 65 | 0) 66 | if e != 0 { 67 | return nil, syscall.Errno(e) 68 | } 69 | 70 | eventfd := &EventFd{fd: int(fd)} 71 | return eventfd, nil 72 | } 73 | 74 | func (fd *EventFd) Close() error { 75 | return syscall.Close(fd.fd) 76 | } 77 | 78 | func (fd *EventFd) Fd() int { 79 | return fd.fd 80 | } 81 | 82 | func (fd *EventFd) Wait() (uint64, error) { 83 | for { 84 | var val uint64 85 | _, _, err := syscall.Syscall( 86 | syscall.SYS_READ, 87 | uintptr(fd.fd), 88 | uintptr(unsafe.Pointer(&val)), 89 | 8) 90 | if err != 0 { 91 | if err == syscall.EAGAIN || err == syscall.EINTR { 92 | continue 93 | } 94 | return 0, err 95 | } 96 | return val, nil 97 | } 98 | 99 | // Unreachable. 100 | return 0, nil 101 | } 102 | 103 | func (fd *EventFd) Signal(val uint64) error { 104 | for { 105 | var val uint64 106 | _, _, err := syscall.Syscall( 107 | syscall.SYS_WRITE, 108 | uintptr(fd.fd), 109 | uintptr(unsafe.Pointer(&val)), 110 | 8) 111 | if err != 0 { 112 | if err == syscall.EAGAIN || err == syscall.EINTR { 113 | continue 114 | } 115 | return err 116 | } 117 | return nil 118 | } 119 | 120 | // Unreachable. 121 | return nil 122 | } 123 | -------------------------------------------------------------------------------- /src/novmm/platform/exits.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package platform 16 | 17 | import ( 18 | "fmt" 19 | ) 20 | 21 | // Exit events. 22 | // When running the vcpu (i.e. vcpu.Run()), you should check 23 | // the return value to see if it matches these types. They should 24 | // be handled appropriate and Run() can be called again to resume. 25 | type ExitUnknown struct { 26 | code uint32 27 | } 28 | 29 | func (exit *ExitUnknown) Error() string { 30 | return fmt.Sprintf("Unknown exit reason: %d", exit.code) 31 | } 32 | 33 | type ExitMmio struct { 34 | addr Paddr 35 | data *uint64 36 | length uint32 37 | write bool 38 | } 39 | 40 | func (exitmmio *ExitMmio) Addr() Paddr { 41 | return exitmmio.addr 42 | } 43 | 44 | func (exitmmio *ExitMmio) Data() *uint64 { 45 | return exitmmio.data 46 | } 47 | 48 | func (exitmmio *ExitMmio) Length() uint { 49 | return uint(exitmmio.length) 50 | } 51 | 52 | func (exitmmio *ExitMmio) IsWrite() bool { 53 | return exitmmio.write 54 | } 55 | 56 | func (exit *ExitMmio) Error() string { 57 | if exit.write { 58 | return fmt.Sprintf( 59 | "Memory-mapped write to %08x (length: %d)", 60 | exit.addr, 61 | exit.length) 62 | } 63 | return fmt.Sprintf( 64 | "Memory-mapped read from %08x (length: %d)", 65 | exit.addr, 66 | exit.length) 67 | } 68 | 69 | type ExitPio struct { 70 | port Paddr 71 | size uint8 72 | data *uint64 73 | out bool 74 | } 75 | 76 | func (exitio *ExitPio) Port() Paddr { 77 | return exitio.port 78 | } 79 | 80 | func (exitio *ExitPio) Size() uint { 81 | return uint(exitio.size) 82 | } 83 | 84 | func (exitio *ExitPio) Data() *uint64 { 85 | return exitio.data 86 | } 87 | 88 | func (exitio *ExitPio) IsOut() bool { 89 | return exitio.out 90 | } 91 | 92 | func (exit *ExitPio) Error() string { 93 | if exit.out { 94 | return fmt.Sprintf( 95 | "Port out to %04x (size: %d)", 96 | exit.port, 97 | exit.size) 98 | } 99 | return fmt.Sprintf( 100 | "Port in from %04x (size: %d)", 101 | exit.port, 102 | exit.size) 103 | } 104 | 105 | type ExitInternalError struct { 106 | code uint32 107 | } 108 | 109 | func (exit *ExitInternalError) Error() string { 110 | return fmt.Sprintf("Internal error: %d", exit.code) 111 | } 112 | 113 | type ExitException struct { 114 | exception uint32 115 | errorCode uint32 116 | } 117 | 118 | func (exit *ExitException) Error() string { 119 | return fmt.Sprintf( 120 | "Exception (exception: %d, error_code: %d)", 121 | exit.exception, 122 | exit.errorCode) 123 | } 124 | 125 | type ExitDebug struct { 126 | } 127 | 128 | func (exit *ExitDebug) Error() string { 129 | return fmt.Sprintf("Debug exit (single-step)") 130 | } 131 | 132 | type ExitShutdown struct { 133 | } 134 | 135 | func (exit *ExitShutdown) Error() string { 136 | return fmt.Sprintf("Shutdown exit") 137 | } 138 | -------------------------------------------------------------------------------- /src/novmm/platform/kvm_caps.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // +build linux 16 | package platform 17 | 18 | /* 19 | #include 20 | 21 | // IOCTL calls. 22 | const int IoctlCheckExtension = KVM_CHECK_EXTENSION; 23 | 24 | // Capabilities (extensions). 25 | const int CapUserMem = KVM_CAP_USER_MEMORY; 26 | const int CapSetIdentityMapAddr = KVM_CAP_SET_IDENTITY_MAP_ADDR; 27 | const int CapIrqChip = KVM_CAP_IRQCHIP; 28 | const int CapIoFd = KVM_CAP_IOEVENTFD; 29 | const int CapIrqFd = KVM_CAP_IRQFD; 30 | const int CapPit2 = KVM_CAP_PIT2; 31 | const int CapPitState2 = KVM_CAP_PIT_STATE2; 32 | const int CapCpuid = KVM_CAP_EXT_CPUID; 33 | const int CapSignalMsi = KVM_CAP_SIGNAL_MSI; 34 | const int CapVcpuEvents = KVM_CAP_VCPU_EVENTS; 35 | const int CapAdjustClock = KVM_CAP_ADJUST_CLOCK; 36 | const int CapXSave = KVM_CAP_XSAVE; 37 | const int CapXcrs = KVM_CAP_XCRS; 38 | */ 39 | import "C" 40 | 41 | import ( 42 | "syscall" 43 | ) 44 | 45 | type kvmCapability struct { 46 | name string 47 | number uintptr 48 | } 49 | 50 | func (capability *kvmCapability) Error() string { 51 | return "Missing capability: " + capability.name 52 | } 53 | 54 | // 55 | // Our required capabilities. 56 | // 57 | // Many of these are actually optional, but none 58 | // of the plumbing has been done to gracefully fail 59 | // when they are not available. For the time being 60 | // development is focused on legacy-free environments, 61 | // so we can split this out when it's necessary later. 62 | // 63 | var requiredCapabilities = []kvmCapability{ 64 | kvmCapability{"User Memory", uintptr(C.CapUserMem)}, 65 | kvmCapability{"Identity Map", uintptr(C.CapSetIdentityMapAddr)}, 66 | kvmCapability{"IRQ Chip", uintptr(C.CapIrqChip)}, 67 | kvmCapability{"IO Event FD", uintptr(C.CapIoFd)}, 68 | kvmCapability{"IRQ Event FD", uintptr(C.CapIrqFd)}, 69 | kvmCapability{"PIT2", uintptr(C.CapPit2)}, 70 | kvmCapability{"PITSTATE2", uintptr(C.CapPitState2)}, 71 | kvmCapability{"Clock", uintptr(C.CapAdjustClock)}, 72 | kvmCapability{"CPUID", uintptr(C.CapCpuid)}, 73 | kvmCapability{"MSI", uintptr(C.CapSignalMsi)}, 74 | kvmCapability{"VCPU Events", uintptr(C.CapVcpuEvents)}, 75 | kvmCapability{"XSAVE", uintptr(C.CapXSave)}, 76 | kvmCapability{"XCRS", uintptr(C.CapXcrs)}, 77 | } 78 | 79 | func checkCapability( 80 | fd int, 81 | capability kvmCapability) error { 82 | 83 | r, _, e := syscall.Syscall( 84 | syscall.SYS_IOCTL, 85 | uintptr(fd), 86 | uintptr(C.IoctlCheckExtension), 87 | capability.number) 88 | if r != 1 || e != 0 { 89 | return &capability 90 | } 91 | 92 | return nil 93 | } 94 | 95 | func checkCapabilities(fd int) error { 96 | // Check our extensions. 97 | for _, capSpec := range requiredCapabilities { 98 | err := checkCapability(fd, capSpec) 99 | if err != nil { 100 | return err 101 | } 102 | } 103 | 104 | return nil 105 | } 106 | -------------------------------------------------------------------------------- /src/novmm/platform/kvm_clock.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package platform 16 | 17 | /* 18 | #include 19 | 20 | // IOCTL calls. 21 | const int IoctlGetClock = KVM_GET_CLOCK; 22 | const int IoctlSetClock = KVM_SET_CLOCK; 23 | */ 24 | import "C" 25 | 26 | import ( 27 | "syscall" 28 | "unsafe" 29 | ) 30 | 31 | // 32 | // Our clock state. 33 | // 34 | type Clock struct { 35 | Time uint64 `json:"time"` 36 | Flags uint32 `json:"flags"` 37 | } 38 | 39 | func (vm *Vm) GetClock() (Clock, error) { 40 | 41 | // Execute the ioctl. 42 | var kvm_clock_data C.struct_kvm_clock_data 43 | _, _, e := syscall.Syscall( 44 | syscall.SYS_IOCTL, 45 | uintptr(vm.fd), 46 | uintptr(C.IoctlGetClock), 47 | uintptr(unsafe.Pointer(&kvm_clock_data))) 48 | if e != 0 { 49 | return Clock{}, e 50 | } 51 | 52 | return Clock{ 53 | Time: uint64(kvm_clock_data.clock), 54 | Flags: uint32(kvm_clock_data.flags), 55 | }, nil 56 | } 57 | 58 | func (vm *Vm) SetClock(clock Clock) error { 59 | 60 | // Execute the ioctl. 61 | var kvm_clock_data C.struct_kvm_clock_data 62 | kvm_clock_data.clock = C.__u64(clock.Time) 63 | kvm_clock_data.flags = C.__u32(clock.Flags) 64 | _, _, e := syscall.Syscall( 65 | syscall.SYS_IOCTL, 66 | uintptr(vm.fd), 67 | uintptr(C.IoctlSetClock), 68 | uintptr(unsafe.Pointer(&kvm_clock_data))) 69 | if e != 0 { 70 | return e 71 | } 72 | 73 | return nil 74 | } 75 | -------------------------------------------------------------------------------- /src/novmm/platform/kvm_cpuid.c: -------------------------------------------------------------------------------- 1 | /* 2 | * cpuid.c 3 | * 4 | * Copyright 2014 Google Inc. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include 20 | #include 21 | #include "kvm_cpuid.h" 22 | 23 | void cpuid_init(void *data, int size) { 24 | struct kvm_cpuid2 *cpuid = (struct kvm_cpuid2*)data; 25 | cpuid->nent = 26 | (size - sizeof(struct kvm_cpuid2)) 27 | / sizeof(struct kvm_cpuid_entry); 28 | } 29 | 30 | int cpuid_get( 31 | void *data, 32 | int n, 33 | __u32 *function, 34 | __u32 *index, 35 | __u32 *flags, 36 | __u32 *eax, 37 | __u32 *ebx, 38 | __u32 *ecx, 39 | __u32 *edx) { 40 | 41 | struct kvm_cpuid2 *cpuid = (struct kvm_cpuid2*)data; 42 | 43 | /* Off the end? */ 44 | if (n >= cpuid->nent) { 45 | return E2BIG; 46 | } 47 | 48 | /* Extract from the structure. */ 49 | *function = cpuid->entries[n].function; 50 | *index = cpuid->entries[n].index; 51 | *flags = cpuid->entries[n].flags; 52 | *eax = cpuid->entries[n].eax; 53 | *ebx = cpuid->entries[n].ebx; 54 | *ecx = cpuid->entries[n].ecx; 55 | *edx = cpuid->entries[n].edx; 56 | 57 | return 0; 58 | } 59 | 60 | void cpuid_native( 61 | __u32 function, 62 | __u32 *eax, 63 | __u32 *ebx, 64 | __u32 *ecx, 65 | __u32 *edx) { 66 | 67 | /* Get our native cpuid. */ 68 | asm volatile("cpuid;" 69 | :"=a"(*eax), 70 | "=b"(*ebx), 71 | "=c"(*ecx), 72 | "=d"(*edx) 73 | :"a"(function)); 74 | } 75 | 76 | int cpuid_set( 77 | void *data, 78 | int size, 79 | int n, 80 | __u32 function, 81 | __u32 index, 82 | __u32 flags, 83 | __u32 eax, 84 | __u32 ebx, 85 | __u32 ecx, 86 | __u32 edx) { 87 | 88 | struct kvm_cpuid2 *cpuid = (struct kvm_cpuid2*)data; 89 | 90 | /* Is it too big? */ 91 | if ((sizeof(struct kvm_cpuid2) + (n+1)*sizeof(struct kvm_cpuid_entry)) > size) { 92 | return ENOMEM; 93 | } 94 | 95 | /* Set the entry as specified. */ 96 | cpuid->entries[n].function = function; 97 | cpuid->entries[n].index = index; 98 | cpuid->entries[n].flags = flags; 99 | cpuid->entries[n].eax = eax; 100 | cpuid->entries[n].ebx = ebx; 101 | cpuid->entries[n].ecx = ecx; 102 | cpuid->entries[n].edx = edx; 103 | cpuid->nent = n+1; 104 | 105 | return 0; 106 | } 107 | -------------------------------------------------------------------------------- /src/novmm/platform/kvm_cpuid.h: -------------------------------------------------------------------------------- 1 | /* 2 | * cpuid.h 3 | * 4 | * Copyright 2014 Google Inc. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | /* Initialize the structure with nents size appropriately. */ 20 | void cpuid_init(void *data, int size); 21 | 22 | /* Extract a cpuid value from the structure. */ 23 | int cpuid_get( 24 | void *data, 25 | int n, 26 | __u32 *function, 27 | __u32 *index, 28 | __u32 *flags, 29 | __u32 *eax, 30 | __u32 *ebx, 31 | __u32 *ecx, 32 | __u32 *edx); 33 | 34 | /* Get a local native cpuid result. */ 35 | void cpuid_native(__u32 function, __u32 *eax, __u32 *ebx, __u32 *ecx, __u32 *edx); 36 | 37 | /* Set a cpuid value within the structure (updating nents). */ 38 | int cpuid_set( 39 | void *data, 40 | int size, 41 | int n, 42 | __u32 function, 43 | __u32 index, 44 | __u32 flags, 45 | __u32 eax, 46 | __u32 ebx, 47 | __u32 ecx, 48 | __u32 edx); 49 | -------------------------------------------------------------------------------- /src/novmm/platform/kvm_eventfd.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // +build linux 16 | package platform 17 | 18 | /* 19 | #include 20 | 21 | // IOCTL calls. 22 | const int IoctlIoEventFd = KVM_IOEVENTFD; 23 | 24 | // IOCTL flags. 25 | const int IoctlIoEventFdFlagPio = KVM_IOEVENTFD_FLAG_PIO; 26 | const int IoctlIoEventFdFlagDatamatch = KVM_IOEVENTFD_FLAG_DATAMATCH; 27 | const int IoctlIoEventFdFlagDeassign = KVM_IOEVENTFD_FLAG_DEASSIGN; 28 | */ 29 | import "C" 30 | 31 | import ( 32 | "syscall" 33 | "unsafe" 34 | ) 35 | 36 | type BoundEventFd struct { 37 | 38 | // Our system eventfd. 39 | *EventFd 40 | 41 | // Our VM reference. 42 | *Vm 43 | 44 | // Address information. 45 | paddr Paddr 46 | size uint 47 | is_pio bool 48 | 49 | // Value information. 50 | has_value bool 51 | value uint64 52 | } 53 | 54 | func (vm *Vm) SetEventFd( 55 | eventfd *EventFd, 56 | paddr Paddr, 57 | size uint, 58 | is_pio bool, 59 | unbind bool, 60 | has_value bool, 61 | value uint64) error { 62 | 63 | var ioeventfd C.struct_kvm_ioeventfd 64 | ioeventfd.addr = C.__u64(paddr) 65 | ioeventfd.len = C.__u32(size) 66 | ioeventfd.fd = C.__s32(eventfd.Fd()) 67 | ioeventfd.datamatch = C.__u64(value) 68 | 69 | if is_pio { 70 | ioeventfd.flags |= C.__u32(C.IoctlIoEventFdFlagPio) 71 | } 72 | if unbind { 73 | ioeventfd.flags |= C.__u32(C.IoctlIoEventFdFlagDeassign) 74 | } 75 | if has_value { 76 | ioeventfd.flags |= C.__u32(C.IoctlIoEventFdFlagDatamatch) 77 | } 78 | 79 | // Bind / unbind the eventfd. 80 | _, _, e := syscall.Syscall( 81 | syscall.SYS_IOCTL, 82 | uintptr(vm.fd), 83 | uintptr(C.IoctlIoEventFd), 84 | uintptr(unsafe.Pointer(&ioeventfd))) 85 | if e != 0 { 86 | return e 87 | } 88 | 89 | // Success. 90 | return nil 91 | } 92 | 93 | func (vm *Vm) NewBoundEventFd( 94 | paddr Paddr, 95 | size uint, 96 | is_pio bool, 97 | has_value bool, 98 | value uint64) (*BoundEventFd, error) { 99 | 100 | // Create our system eventfd. 101 | eventfd, err := NewEventFd() 102 | if err != nil { 103 | return nil, err 104 | } 105 | 106 | // Bind the eventfd. 107 | err = vm.SetEventFd( 108 | eventfd, 109 | paddr, 110 | size, 111 | is_pio, 112 | false, 113 | has_value, 114 | value) 115 | if err != nil { 116 | eventfd.Close() 117 | return nil, err 118 | } 119 | 120 | // Return our bound event. 121 | return &BoundEventFd{ 122 | EventFd: eventfd, 123 | Vm: vm, 124 | paddr: paddr, 125 | size: size, 126 | is_pio: is_pio, 127 | has_value: has_value, 128 | value: value, 129 | }, nil 130 | } 131 | 132 | func (fd *BoundEventFd) Close() error { 133 | 134 | // Unbind the event. 135 | err := fd.Vm.SetEventFd( 136 | fd.EventFd, 137 | fd.paddr, 138 | fd.size, 139 | fd.is_pio, 140 | true, 141 | fd.has_value, 142 | fd.value) 143 | if err != nil { 144 | return err 145 | } 146 | 147 | // Close the eventfd. 148 | return fd.Close() 149 | } 150 | -------------------------------------------------------------------------------- /src/novmm/platform/kvm_exits.c: -------------------------------------------------------------------------------- 1 | /* 2 | * kvm_exits.c 3 | * 4 | * Copyright 2014 Google Inc. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include "kvm_exits.h" 20 | 21 | /* Exit reasons. */ 22 | const int ExitReasonMmio = KVM_EXIT_MMIO; 23 | const int ExitReasonIo = KVM_EXIT_IO; 24 | const int ExitReasonInternalError = KVM_EXIT_INTERNAL_ERROR; 25 | const int ExitReasonException = KVM_EXIT_EXCEPTION; 26 | const int ExitReasonDebug = KVM_EXIT_DEBUG; 27 | const int ExitReasonShutdown = KVM_EXIT_SHUTDOWN; 28 | 29 | void* handle_exit_mmio(struct kvm_run* kvm) { 30 | return kvmExitMmio( 31 | kvm->mmio.phys_addr, 32 | ((__u64*)&(kvm->mmio.data[0])), 33 | kvm->mmio.len, 34 | kvm->mmio.is_write); 35 | } 36 | 37 | void* handle_exit_io(struct kvm_run* kvm) { 38 | return kvmExitPio( 39 | kvm->io.port, 40 | kvm->io.size, 41 | (void*)((unsigned long long)kvm + (unsigned long long)kvm->io.data_offset), 42 | kvm->io.count, 43 | kvm->io.direction == KVM_EXIT_IO_OUT); 44 | } 45 | 46 | void* handle_exit_internal_error(struct kvm_run* kvm) { 47 | return kvmExitInternalError(kvm->internal.suberror); 48 | } 49 | 50 | void* handle_exit_exception(struct kvm_run* kvm) { 51 | return kvmExitException(kvm->ex.exception, kvm->ex.error_code); 52 | } 53 | 54 | void* handle_exit_unknown(struct kvm_run* kvm) { 55 | return kvmExitUnknown(kvm->exit_reason); 56 | } 57 | -------------------------------------------------------------------------------- /src/novmm/platform/kvm_exits.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // +build linux 16 | package platform 17 | 18 | /* 19 | #include "kvm_exits.h" 20 | #include 21 | */ 22 | import "C" 23 | 24 | import ( 25 | "unsafe" 26 | ) 27 | 28 | //export kvmExitMmio 29 | func kvmExitMmio( 30 | addr C.__u64, 31 | data *C.__u64, 32 | length C.__u32, 33 | write C.int) unsafe.Pointer { 34 | 35 | return unsafe.Pointer(&ExitMmio{ 36 | addr: Paddr(addr), 37 | data: (*uint64)(data), 38 | length: uint32(length), 39 | write: write != C.int(0), 40 | }) 41 | } 42 | 43 | //export kvmExitPio 44 | func kvmExitPio( 45 | port C.__u16, 46 | size C.__u8, 47 | data unsafe.Pointer, 48 | length C.__u32, 49 | out C.int) unsafe.Pointer { 50 | 51 | return unsafe.Pointer(&ExitPio{ 52 | port: Paddr(port), 53 | size: uint8(size), 54 | data: (*uint64)(data), 55 | out: out != C.int(0), 56 | }) 57 | } 58 | 59 | //export kvmExitInternalError 60 | func kvmExitInternalError( 61 | code C.__u32) unsafe.Pointer { 62 | 63 | return unsafe.Pointer(&ExitInternalError{ 64 | code: uint32(code), 65 | }) 66 | } 67 | 68 | //export kvmExitException 69 | func kvmExitException( 70 | exception C.__u32, 71 | error_code C.__u32) unsafe.Pointer { 72 | 73 | return unsafe.Pointer(&ExitException{ 74 | exception: uint32(exception), 75 | errorCode: uint32(error_code), 76 | }) 77 | } 78 | 79 | //export kvmExitUnknown 80 | func kvmExitUnknown( 81 | code C.__u32) unsafe.Pointer { 82 | 83 | return unsafe.Pointer(&ExitUnknown{ 84 | code: uint32(code), 85 | }) 86 | } 87 | 88 | func (vcpu *Vcpu) GetExitError() error { 89 | // Handle the error. 90 | switch C.int(vcpu.kvm.exit_reason) { 91 | case C.ExitReasonMmio: 92 | return (*ExitMmio)(C.handle_exit_mmio(vcpu.kvm)) 93 | case C.ExitReasonIo: 94 | return (*ExitPio)(C.handle_exit_io(vcpu.kvm)) 95 | case C.ExitReasonInternalError: 96 | return (*ExitInternalError)(C.handle_exit_internal_error(vcpu.kvm)) 97 | case C.ExitReasonException: 98 | return (*ExitException)(C.handle_exit_exception(vcpu.kvm)) 99 | case C.ExitReasonDebug: 100 | return &ExitDebug{} 101 | case C.ExitReasonShutdown: 102 | return &ExitShutdown{} 103 | default: 104 | return (*ExitUnknown)(C.handle_exit_unknown(vcpu.kvm)) 105 | } 106 | 107 | // Unreachable. 108 | return nil 109 | } 110 | -------------------------------------------------------------------------------- /src/novmm/platform/kvm_exits.h: -------------------------------------------------------------------------------- 1 | /* 2 | * kvm_exits.h 3 | * 4 | * These stubs help interpret KVM exits. 5 | * 6 | * Copyright 2014 Google Inc. All rights reserved. 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | 21 | #include 22 | 23 | extern void* kvmExitMmio(__u64 addr, __u64* data, __u32 length, int write); 24 | extern void* kvmExitPio(__u16 port, __u8 size, void* data, __u32 length, int out); 25 | extern void* kvmExitInternalError(__u32 code); 26 | extern void* kvmExitException(__u32 exception, __u32 error_code); 27 | extern void* kvmExitUnknown(__u32 code); 28 | 29 | extern const int ExitReasonMmio; 30 | extern const int ExitReasonIo; 31 | extern const int ExitReasonInternalError; 32 | extern const int ExitReasonDebug; 33 | extern const int ExitReasonException; 34 | extern const int ExitReasonShutdown; 35 | 36 | void* handle_exit_mmio(struct kvm_run* kvm); 37 | void* handle_exit_io(struct kvm_run* kvm); 38 | void* handle_exit_internal_error(struct kvm_run* kvm); 39 | void* handle_exit_exception(struct kvm_run* kvm); 40 | void* handle_exit_unknown(struct kvm_run* kvm); 41 | -------------------------------------------------------------------------------- /src/novmm/platform/kvm_fpu.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package platform 16 | 17 | /* 18 | #include 19 | 20 | const int IoctlGetFpu = KVM_GET_FPU; 21 | const int IoctlSetFpu = KVM_SET_FPU; 22 | */ 23 | import "C" 24 | 25 | import ( 26 | "syscall" 27 | "unsafe" 28 | ) 29 | 30 | // 31 | // Our FPU state. 32 | // 33 | type Fpu struct { 34 | FPR [8][16]uint8 35 | FCW uint16 36 | FSW uint16 37 | FTWX uint8 38 | 39 | LastOpcode uint16 `json:"last-opcode"` 40 | LastIp uint64 `json:"last-ip"` 41 | LastDp uint64 `json:"last-dp"` 42 | 43 | XMM [16][16]uint8 44 | MXCSR uint32 45 | } 46 | 47 | func (vcpu *Vcpu) GetFpuState() (Fpu, error) { 48 | 49 | // Execute the ioctl. 50 | var kvm_fpu C.struct_kvm_fpu 51 | _, _, e := syscall.Syscall( 52 | syscall.SYS_IOCTL, 53 | uintptr(vcpu.fd), 54 | uintptr(C.IoctlGetFpu), 55 | uintptr(unsafe.Pointer(&kvm_fpu))) 56 | if e != 0 { 57 | return Fpu{}, e 58 | } 59 | 60 | // Transform our state. 61 | state := Fpu{} 62 | 63 | for i := 0; i < len(state.FPR); i += 1 { 64 | for j := 0; j < len(state.FPR[i]); j += 1 { 65 | state.FPR[i][j] = uint8(kvm_fpu.fpr[i][j]) 66 | } 67 | } 68 | state.FCW = uint16(kvm_fpu.fcw) 69 | state.FSW = uint16(kvm_fpu.fsw) 70 | state.FTWX = uint8(kvm_fpu.ftwx) 71 | state.LastOpcode = uint16(kvm_fpu.last_opcode) 72 | state.LastIp = uint64(kvm_fpu.last_ip) 73 | state.LastDp = uint64(kvm_fpu.last_dp) 74 | for i := 0; i < len(state.XMM); i += 1 { 75 | for j := 0; j < len(state.XMM[i]); j += 1 { 76 | state.XMM[i][j] = uint8(kvm_fpu.xmm[i][j]) 77 | } 78 | } 79 | state.MXCSR = uint32(kvm_fpu.mxcsr) 80 | 81 | return state, nil 82 | } 83 | 84 | func (vcpu *Vcpu) SetFpuState(state Fpu) error { 85 | 86 | // Prepare our data. 87 | var kvm_fpu C.struct_kvm_fpu 88 | for i := 0; i < len(state.FPR); i += 1 { 89 | for j := 0; j < len(state.FPR[i]); j += 1 { 90 | kvm_fpu.fpr[i][j] = C.__u8(state.FPR[i][j]) 91 | } 92 | } 93 | kvm_fpu.fcw = C.__u16(state.FCW) 94 | kvm_fpu.fsw = C.__u16(state.FSW) 95 | kvm_fpu.ftwx = C.__u8(state.FTWX) 96 | kvm_fpu.last_opcode = C.__u16(state.LastOpcode) 97 | kvm_fpu.last_ip = C.__u64(state.LastIp) 98 | kvm_fpu.last_dp = C.__u64(state.LastDp) 99 | for i := 0; i < len(state.XMM); i += 1 { 100 | for j := 0; j < len(state.XMM[i]); j += 1 { 101 | kvm_fpu.xmm[i][j] = C.__u8(state.XMM[i][j]) 102 | } 103 | } 104 | kvm_fpu.mxcsr = C.__u32(state.MXCSR) 105 | 106 | // Execute the ioctl. 107 | _, _, e := syscall.Syscall( 108 | syscall.SYS_IOCTL, 109 | uintptr(vcpu.fd), 110 | uintptr(C.IoctlSetFpu), 111 | uintptr(unsafe.Pointer(&kvm_fpu))) 112 | if e != 0 { 113 | return e 114 | } 115 | 116 | return nil 117 | } 118 | -------------------------------------------------------------------------------- /src/novmm/platform/kvm_memory.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // +build linux 16 | package platform 17 | 18 | /* 19 | #include 20 | 21 | // IOCTL calls. 22 | const int IoctlSetUserMemoryRegion = KVM_SET_USER_MEMORY_REGION; 23 | const int IoctlTranslate = KVM_TRANSLATE; 24 | 25 | // IOCTL flags. 26 | const int IoctlFlagMemLogDirtyPages = KVM_MEM_LOG_DIRTY_PAGES; 27 | */ 28 | import "C" 29 | 30 | import ( 31 | "syscall" 32 | "unsafe" 33 | ) 34 | 35 | func (vm *Vm) MapUserMemory( 36 | start Paddr, 37 | size uint64, 38 | mmap []byte) error { 39 | 40 | // See NOTE above about read-only memory. 41 | // As we will not support it for the moment, 42 | // we do not expose it through the interface. 43 | // Leveraging that feature will likely require 44 | // a small amount of re-architecting in any case. 45 | var region C.struct_kvm_userspace_memory_region 46 | region.slot = C.__u32(vm.mem_region) 47 | region.flags = C.__u32(0) 48 | region.guest_phys_addr = C.__u64(start) 49 | region.memory_size = C.__u64(size) 50 | region.userspace_addr = C.__u64(uintptr(unsafe.Pointer(&mmap[0]))) 51 | 52 | // Execute the ioctl. 53 | _, _, e := syscall.Syscall( 54 | syscall.SYS_IOCTL, 55 | uintptr(vm.fd), 56 | uintptr(C.IoctlSetUserMemoryRegion), 57 | uintptr(unsafe.Pointer(®ion))) 58 | if e != 0 { 59 | return e 60 | } 61 | 62 | // We're set, bump our slot. 63 | vm.mem_region += 1 64 | return nil 65 | } 66 | 67 | func (vm *Vm) MapReservedMemory( 68 | start Paddr, 69 | size uint64) error { 70 | 71 | // Nothing to do. 72 | return nil 73 | } 74 | 75 | func (vcpu *Vcpu) Translate( 76 | vaddr Vaddr) (Paddr, bool, bool, bool, error) { 77 | 78 | // Perform the translation. 79 | var translation C.struct_kvm_translation 80 | translation.linear_address = C.__u64(vaddr) 81 | _, _, e := syscall.Syscall( 82 | syscall.SYS_IOCTL, 83 | uintptr(vcpu.fd), 84 | uintptr(C.IoctlTranslate), 85 | uintptr(unsafe.Pointer(&translation))) 86 | if e != 0 { 87 | return Paddr(0), false, false, false, e 88 | } 89 | 90 | paddr := Paddr(translation.physical_address) 91 | valid := translation.valid != C.__u8(0) 92 | writeable := translation.writeable != C.__u8(0) 93 | usermode := translation.valid != C.__u8(0) 94 | 95 | return paddr, valid, writeable, usermode, nil 96 | } 97 | -------------------------------------------------------------------------------- /src/novmm/platform/kvm_mpstate.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package platform 16 | 17 | /* 18 | #include 19 | #include "cpuid.h" 20 | 21 | // IOCTL calls. 22 | const int IoctlGetMpState = KVM_GET_MP_STATE; 23 | const int IoctlSetMpState = KVM_SET_MP_STATE; 24 | 25 | // States. 26 | const int MpStateRunnable = KVM_MP_STATE_RUNNABLE; 27 | const int MpStateUninitialized = KVM_MP_STATE_UNINITIALIZED; 28 | const int MpStateInitReceived = KVM_MP_STATE_INIT_RECEIVED; 29 | const int MpStateHalted = KVM_MP_STATE_HALTED; 30 | const int MpStateSipiReceived = KVM_MP_STATE_SIPI_RECEIVED; 31 | */ 32 | import "C" 33 | 34 | import ( 35 | "encoding/json" 36 | "syscall" 37 | "unsafe" 38 | ) 39 | 40 | // 41 | // Our vcpus state. 42 | // 43 | type MpState C.int 44 | 45 | var MpStateRunnable = MpState(C.MpStateRunnable) 46 | var MpStateUninitialized = MpState(C.MpStateUninitialized) 47 | var MpStateInitReceived = MpState(C.MpStateInitReceived) 48 | var MpStateHalted = MpState(C.MpStateHalted) 49 | var MpStateSipiReceived = MpState(C.MpStateSipiReceived) 50 | 51 | var stateMap = map[MpState]string{ 52 | MpStateRunnable: "runnable", 53 | MpStateUninitialized: "uninitialized", 54 | MpStateInitReceived: "init-received", 55 | MpStateHalted: "halted", 56 | MpStateSipiReceived: "sipi-received", 57 | } 58 | 59 | var stateRevMap = map[string]MpState{ 60 | "runnable": MpStateRunnable, 61 | "uninitialized": MpStateUninitialized, 62 | "init-received": MpStateInitReceived, 63 | "halted": MpStateHalted, 64 | "sipi-received": MpStateSipiReceived, 65 | } 66 | 67 | func (vcpu *Vcpu) GetMpState() (MpState, error) { 68 | 69 | // Execute the ioctl. 70 | var kvm_state C.struct_kvm_mp_state 71 | _, _, e := syscall.Syscall( 72 | syscall.SYS_IOCTL, 73 | uintptr(vcpu.fd), 74 | uintptr(C.IoctlGetMpState), 75 | uintptr(unsafe.Pointer(&kvm_state))) 76 | if e != 0 { 77 | return MpState(kvm_state.mp_state), e 78 | } 79 | 80 | return MpState(kvm_state.mp_state), nil 81 | } 82 | 83 | func (vcpu *Vcpu) SetMpState(state MpState) error { 84 | 85 | // Execute the ioctl. 86 | var kvm_state C.struct_kvm_mp_state 87 | kvm_state.mp_state = C.__u32(state) 88 | _, _, e := syscall.Syscall( 89 | syscall.SYS_IOCTL, 90 | uintptr(vcpu.fd), 91 | uintptr(C.IoctlSetMpState), 92 | uintptr(unsafe.Pointer(&kvm_state))) 93 | if e != 0 { 94 | return e 95 | } 96 | 97 | return nil 98 | } 99 | 100 | func (state *MpState) MarshalJSON() ([]byte, error) { 101 | 102 | // Marshal as a string. 103 | value, ok := stateMap[*state] 104 | if !ok { 105 | return nil, UnknownState 106 | } 107 | 108 | return json.Marshal(value) 109 | } 110 | 111 | func (state *MpState) UnmarshalJSON(data []byte) error { 112 | 113 | // Unmarshal as an string. 114 | var value string 115 | err := json.Unmarshal(data, &value) 116 | if err != nil { 117 | return err 118 | } 119 | 120 | // Find the state. 121 | newstate, ok := stateRevMap[value] 122 | if !ok { 123 | return UnknownState 124 | } 125 | 126 | // That's our state. 127 | *state = newstate 128 | return nil 129 | } 130 | -------------------------------------------------------------------------------- /src/novmm/platform/kvm_msrs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * msrs.c 3 | * 4 | * Copyright 2014 Google Inc. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include 20 | #include "kvm_msrs.h" 21 | 22 | int msr_size(void) { 23 | return sizeof(struct kvm_msrs) + sizeof(struct kvm_msr_entry); 24 | } 25 | 26 | void msr_set(void *data, __u32 index, __u64 value) { 27 | struct kvm_msrs *msrs = (struct kvm_msrs*)data; 28 | 29 | /* Set as a single value. */ 30 | msrs->nmsrs = 1; 31 | msrs->entries[0].index = index; 32 | msrs->entries[0].data = value; 33 | } 34 | 35 | __u64 msr_get(void *data) { 36 | struct kvm_msrs *msrs = (struct kvm_msrs*)data; 37 | 38 | /* Return the (assumed valid) value. */ 39 | return msrs->entries[0].data; 40 | } 41 | 42 | int msr_list_index(void *data, int n, __u32 *index) { 43 | struct kvm_msr_list *msrs = (struct kvm_msr_list*)data; 44 | 45 | /* More than we have? */ 46 | if (n >= msrs->nmsrs) { 47 | return 1; 48 | } 49 | 50 | /* Return the given index. */ 51 | *index = msrs->indices[n]; 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /src/novmm/platform/kvm_msrs.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package platform 16 | 17 | /* 18 | #include 19 | #include "kvm_msrs.h" 20 | 21 | const int IoctlGetMsrIndexList = KVM_GET_MSR_INDEX_LIST; 22 | const int IoctlSetMsrs = KVM_SET_MSRS; 23 | const int IoctlGetMsrs = KVM_GET_MSRS; 24 | */ 25 | import "C" 26 | 27 | import ( 28 | "syscall" 29 | "unsafe" 30 | ) 31 | 32 | type Msr struct { 33 | Index uint32 `json:"index"` 34 | Value uint64 `json:"value"` 35 | } 36 | 37 | func availableMsrs(fd int) ([]uint32, error) { 38 | 39 | // Find our list of MSR indices. 40 | // A page should be more than enough here, 41 | // eventually if it's not we'll end up with 42 | // a failed system call for some reason other 43 | // than E2BIG (which just says n is wrong). 44 | msrIndices := make([]byte, PageSize, PageSize) 45 | msrs := make([]uint32, 0, 0) 46 | 47 | for { 48 | _, _, e := syscall.Syscall( 49 | syscall.SYS_IOCTL, 50 | uintptr(fd), 51 | uintptr(C.IoctlGetMsrIndexList), 52 | uintptr(unsafe.Pointer(&msrIndices[0]))) 53 | if e == syscall.E2BIG { 54 | // The nmsrs field will now have been 55 | // adjusted, and we can run it again. 56 | continue 57 | } else if e != 0 { 58 | return nil, e 59 | } 60 | 61 | // We're good! 62 | break 63 | } 64 | 65 | // Extract each msr individually. 66 | for i := 0; ; i += 1 { 67 | // Is there a valid index? 68 | var index C.__u32 69 | e := C.msr_list_index( 70 | unsafe.Pointer(&msrIndices[0]), 71 | C.int(i), 72 | &index) 73 | 74 | // Any left? 75 | if e != 0 { 76 | break 77 | } 78 | 79 | // Add this MSR. 80 | msrs = append(msrs, uint32(index)) 81 | } 82 | 83 | return msrs, nil 84 | } 85 | 86 | func (vcpu *Vcpu) GetMsr(index uint32) (uint64, error) { 87 | 88 | // Setup our structure. 89 | data := make([]byte, C.msr_size(), C.msr_size()) 90 | 91 | // Set our index to retrieve. 92 | C.msr_set(unsafe.Pointer(&data[0]), C.__u32(index), C.__u64(0)) 93 | 94 | // Execute our ioctl. 95 | _, _, e := syscall.Syscall( 96 | syscall.SYS_IOCTL, 97 | uintptr(vcpu.fd), 98 | uintptr(C.IoctlGetMsrs), 99 | uintptr(unsafe.Pointer(&data[0]))) 100 | if e != 0 { 101 | return 0, e 102 | } 103 | 104 | // Return our value. 105 | return uint64(C.msr_get(unsafe.Pointer(&data[0]))), nil 106 | } 107 | 108 | func (vcpu *Vcpu) SetMsr(index uint32, value uint64) error { 109 | 110 | // Setup our structure. 111 | data := make([]byte, C.msr_size(), C.msr_size()) 112 | 113 | // Set our index and value. 114 | C.msr_set(unsafe.Pointer(&data[0]), C.__u32(index), C.__u64(value)) 115 | 116 | // Execute our ioctl. 117 | _, _, e := syscall.Syscall( 118 | syscall.SYS_IOCTL, 119 | uintptr(vcpu.fd), 120 | uintptr(C.IoctlSetMsrs), 121 | uintptr(unsafe.Pointer(&data[0]))) 122 | if e != 0 { 123 | return e 124 | } 125 | 126 | return nil 127 | } 128 | 129 | func (vcpu *Vcpu) GetMsrs() ([]Msr, error) { 130 | 131 | // Extract each msr individually. 132 | msrs := make([]Msr, 0, len(vcpu.msrs)) 133 | 134 | for _, index := range vcpu.msrs { 135 | 136 | // Get this MSR. 137 | value, err := vcpu.GetMsr(index) 138 | if err != nil { 139 | return msrs, err 140 | } 141 | 142 | // Got one. 143 | msrs = append(msrs, Msr{uint32(index), uint64(value)}) 144 | } 145 | 146 | // Finish it off. 147 | return msrs, nil 148 | } 149 | 150 | func (vcpu *Vcpu) SetMsrs(msrs []Msr) error { 151 | 152 | for _, msr := range msrs { 153 | // Set our msrs. 154 | err := vcpu.SetMsr(msr.Index, msr.Value) 155 | if err != nil { 156 | return err 157 | } 158 | } 159 | 160 | return nil 161 | } 162 | -------------------------------------------------------------------------------- /src/novmm/platform/kvm_msrs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * msrs.h 3 | * 4 | * Copyright 2014 Google Inc. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | /* Return the value needed for a single MSR entry. */ 20 | int msr_size(void); 21 | 22 | /* Set the index and value for a single MSR entry. */ 23 | void msr_set(void *data, __u32 index, __u64 value); 24 | 25 | /* Extract the value from a single MSR entry. */ 26 | __u64 msr_get(void *data); 27 | 28 | /* Extract an index from an MSR list. */ 29 | int msr_list_index(void *data, int n, __u32 *index); 30 | -------------------------------------------------------------------------------- /src/novmm/platform/kvm_pit.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // +build linux 16 | package platform 17 | 18 | /* 19 | #include 20 | 21 | // IOCTL calls. 22 | const int IoctlCreatePit2 = KVM_CREATE_PIT2; 23 | const int IoctlGetPit2 = KVM_GET_PIT2; 24 | const int IoctlSetPit2 = KVM_SET_PIT2; 25 | 26 | // Size of pit state. 27 | const int PitSize = sizeof(struct kvm_pit_state2); 28 | */ 29 | import "C" 30 | 31 | import ( 32 | "syscall" 33 | "unsafe" 34 | ) 35 | 36 | // 37 | // PitState -- 38 | // 39 | // We represent the PitState as a blob. 40 | // This representation should be relatively 41 | // safe from a forward-compatibility perspective, 42 | // as KVM internally will take care of reserving 43 | // bits and ensuring compatibility, etc. 44 | // 45 | type PitState struct { 46 | Data []byte `json:"data"` 47 | } 48 | 49 | func (vm *Vm) CreatePit() error { 50 | // Prepare the PIT config. 51 | // The only flag supported at the time of writing 52 | // was KVM_PIT_SPEAKER_DUMMY, which I really have no 53 | // interest in supporting. 54 | var pit C.struct_kvm_pit_config 55 | pit.flags = C.__u32(0) 56 | 57 | // Execute the ioctl. 58 | _, _, e := syscall.Syscall( 59 | syscall.SYS_IOCTL, 60 | uintptr(vm.fd), 61 | uintptr(C.IoctlCreatePit2), 62 | uintptr(unsafe.Pointer(&pit))) 63 | if e != 0 { 64 | return e 65 | } 66 | 67 | return nil 68 | } 69 | 70 | func (vm *Vm) GetPit() (PitState, error) { 71 | 72 | // Prepare the pit state. 73 | state := PitState{make([]byte, C.PitSize, C.PitSize)} 74 | 75 | // Execute the ioctl. 76 | _, _, e := syscall.Syscall( 77 | syscall.SYS_IOCTL, 78 | uintptr(vm.fd), 79 | uintptr(C.IoctlGetPit2), 80 | uintptr(unsafe.Pointer(&state.Data[0]))) 81 | if e != 0 { 82 | return state, e 83 | } 84 | 85 | return state, nil 86 | } 87 | 88 | func (vm *Vm) SetPit(state PitState) error { 89 | 90 | // Is there any state to set? 91 | // We just eat this error, it's fine. 92 | if state.Data == nil { 93 | return nil 94 | } 95 | 96 | // Is this the right size? 97 | if len(state.Data) != int(C.PitSize) { 98 | return PitIncompatible 99 | } 100 | 101 | // Execute the ioctl. 102 | _, _, e := syscall.Syscall( 103 | syscall.SYS_IOCTL, 104 | uintptr(vm.fd), 105 | uintptr(C.IoctlSetPit2), 106 | uintptr(unsafe.Pointer(&state.Data[0]))) 107 | if e != 0 { 108 | return e 109 | } 110 | 111 | return nil 112 | } 113 | -------------------------------------------------------------------------------- /src/novmm/platform/kvm_run.c: -------------------------------------------------------------------------------- 1 | /* 2 | * kvm_run.c 3 | * 4 | * Copyright 2014 Google Inc. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "kvm_run.h" 28 | 29 | int kvm_run_init(int vcpufd, struct kvm_run_info *info) { 30 | int rval = 0; 31 | sigset_t set; 32 | struct kvm_signal_mask *arg; 33 | 34 | arg = malloc(sizeof(*arg) + sizeof(set)); 35 | if (arg == NULL) { 36 | return ENOMEM; 37 | } 38 | 39 | /* Initialize our lock. */ 40 | if (pthread_mutex_init(&info->lock, NULL) < 0) { 41 | return errno; 42 | } 43 | 44 | /* Enable all signals. */ 45 | sigemptyset(&set); 46 | arg->len = 8; 47 | memcpy(arg->sigset, &set, sizeof(set)); 48 | 49 | /* Set the mask during KVM_RUN. */ 50 | rval = ioctl(vcpufd, KVM_SET_SIGNAL_MASK, arg); 51 | free(arg); 52 | 53 | return rval < 0 ? errno : 0; 54 | } 55 | 56 | int kvm_run(int vcpufd, int sig, struct kvm_run_info *info) { 57 | int rval = 0; 58 | sigset_t newset; 59 | sigset_t oldset; 60 | 61 | /* Acquire our lock. */ 62 | pthread_mutex_lock(&info->lock); 63 | 64 | /* Did we receive a cancel request? */ 65 | if (info->cancel) { 66 | info->cancel = 0; 67 | pthread_mutex_unlock(&info->lock); 68 | return EINTR; 69 | } 70 | 71 | /* Block our interrupt signal temporarily. */ 72 | sigemptyset(&newset); 73 | sigaddset(&newset, sig); 74 | if (pthread_sigmask(SIG_BLOCK, &newset, &oldset) < 0) { 75 | pthread_mutex_unlock(&info->lock); 76 | return errno; 77 | } 78 | 79 | /* Save our tid. */ 80 | info->tid = pthread_self(); 81 | info->running = 1; 82 | 83 | /* Drop our lock, we're now "running". 84 | * After the signal was blocked above, we 85 | * were guaranteed that anyone who acquires 86 | * the lock, reads the TID and does a kill 87 | * will actually interrupt the KVM_RUN. */ 88 | pthread_mutex_unlock(&info->lock); 89 | 90 | /* Enter into guest mode. */ 91 | rval = ioctl(vcpufd, KVM_RUN, 0); 92 | if (rval < 0) { 93 | rval = errno; 94 | } 95 | 96 | /* Reacquire our lock. */ 97 | pthread_mutex_lock(&info->lock); 98 | 99 | /* Note that we are no longer running. 100 | * It's quite possible that prior to acquiring 101 | * the lock above, someone ma hit us with another 102 | * signal. This is okay, it will be consumed after 103 | * we unblock the signal block (harmlessly). */ 104 | info->running = 0; 105 | info->cancel = 0; 106 | 107 | /* Done with clearing running & cancel. */ 108 | pthread_mutex_unlock(&info->lock); 109 | 110 | /* Unblock the interrupt signal signal. */ 111 | if (pthread_sigmask(SIG_SETMASK, &oldset, NULL) < 0) { 112 | return rval != 0 ? rval : errno; 113 | } 114 | 115 | return rval; 116 | } 117 | 118 | int kvm_run_interrupt(int vcpufd, int sig, struct kvm_run_info *info) { 119 | (void)vcpufd; 120 | 121 | /* Acquire our lock. */ 122 | pthread_mutex_lock(&info->lock); 123 | 124 | /* Is this thread running? */ 125 | if (info->running) { 126 | pthread_kill(info->tid, sig); 127 | } else { 128 | info->cancel = 1; 129 | } 130 | 131 | /* We're done. */ 132 | pthread_mutex_unlock(&info->lock); 133 | } 134 | -------------------------------------------------------------------------------- /src/novmm/platform/kvm_run.h: -------------------------------------------------------------------------------- 1 | /* 2 | * kvm_run.h 3 | * 4 | * C-stub to enter into guest mode. 5 | * 6 | * This exists because of complexities around go-routine 7 | * scheduling and the ability to deliver a signal to a specific 8 | * thread. Because we are not able to control this from Go, 9 | * we need to isolate some calls in C for pause/unpause control. 10 | * 11 | * Copyright 2014 Google Inc. All rights reserved. 12 | * 13 | * Licensed under the Apache License, Version 2.0 (the "License"); 14 | * you may not use this file except in compliance with the License. 15 | * You may obtain a copy of the License at 16 | * 17 | * http://www.apache.org/licenses/LICENSE-2.0 18 | * 19 | * Unless required by applicable law or agreed to in writing, software 20 | * distributed under the License is distributed on an "AS IS" BASIS, 21 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 22 | * See the License for the specific language governing permissions and 23 | * limitations under the License. 24 | */ 25 | 26 | #include 27 | #include 28 | 29 | struct kvm_run_info { 30 | volatile int running; 31 | volatile int cancel; 32 | volatile pthread_t tid; 33 | 34 | pthread_mutex_t lock; 35 | }; 36 | 37 | /* Initialize the signal mask. */ 38 | int kvm_run_init(int vcpufd, struct kvm_run_info *info); 39 | 40 | /* Prepare for entering guest mode. */ 41 | int kvm_run_prep(int vcpufd, struct kvm_run_info *info); 42 | 43 | /* Save our tid and enter guest mode. */ 44 | int kvm_run(int vcpufd, int sig, struct kvm_run_info *info); 45 | 46 | /* Interrupt the running vcpu. */ 47 | int kvm_run_interrupt(int vcpufd, int sig, struct kvm_run_info *info); 48 | -------------------------------------------------------------------------------- /src/novmm/platform/kvm_vcpu.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // +build linux 16 | package platform 17 | 18 | /* 19 | #include 20 | 21 | // IOCTL calls. 22 | const int IoctlCreateVcpu = KVM_CREATE_VCPU; 23 | const int IoctlSetGuestDebug = KVM_SET_GUEST_DEBUG; 24 | 25 | // IOCTL flags. 26 | const int IoctlGuestDebugEnable = KVM_GUESTDBG_ENABLE|KVM_GUESTDBG_SINGLESTEP; 27 | */ 28 | import "C" 29 | 30 | import ( 31 | "syscall" 32 | "unsafe" 33 | ) 34 | 35 | type Vcpu struct { 36 | // The VCPU id. 37 | Id uint 38 | 39 | // The VCPU fd. 40 | fd int 41 | 42 | // The mmap-structure. 43 | // NOTE: mmap is the go pointer to the bytes, 44 | // kvm points to same data but is interpreted. 45 | mmap []byte 46 | kvm *C.struct_kvm_run 47 | 48 | // Cached registers. 49 | // See data.go for the serialization code. 50 | regs C.struct_kvm_regs 51 | sregs C.struct_kvm_sregs 52 | 53 | // Caching parameters. 54 | regs_cached bool 55 | sregs_cached bool 56 | regs_dirty bool 57 | sregs_dirty bool 58 | 59 | // Our available MSRs. 60 | msrs []uint32 61 | 62 | // Our default cpuid. 63 | cpuid []Cpuid 64 | 65 | // Is this stepping? 66 | is_stepping bool 67 | 68 | // Our run information. 69 | RunInfo 70 | } 71 | 72 | func (vm *Vm) NewVcpu(id uint) (*Vcpu, error) { 73 | 74 | // Create a new Vcpu. 75 | vcpufd, _, e := syscall.Syscall( 76 | syscall.SYS_IOCTL, 77 | uintptr(vm.fd), 78 | uintptr(C.IoctlCreateVcpu), 79 | uintptr(id)) 80 | if e != 0 { 81 | return nil, e 82 | } 83 | 84 | // Make sure this disappears on exec. 85 | // This is a race condition here, but realistically 86 | // we are not going to be restarting at this point. 87 | syscall.CloseOnExec(int(vcpufd)) 88 | 89 | // Map our shared data. 90 | mmap, err := syscall.Mmap( 91 | int(vcpufd), 92 | 0, 93 | vm.mmap_size, 94 | syscall.PROT_READ|syscall.PROT_WRITE, 95 | syscall.MAP_SHARED) 96 | if err != nil { 97 | syscall.Close(int(vcpufd)) 98 | return nil, err 99 | } 100 | kvm_run := (*C.struct_kvm_run)(unsafe.Pointer(&mmap[0])) 101 | 102 | // Add our Vcpu. 103 | vcpu := &Vcpu{ 104 | Id: id, 105 | fd: int(vcpufd), 106 | mmap: mmap, 107 | kvm: kvm_run, 108 | msrs: vm.msrs, 109 | cpuid: vm.cpuid, 110 | } 111 | vm.vcpus = append(vm.vcpus, vcpu) 112 | 113 | // Set our default cpuid. 114 | // (This may be overriden later). 115 | err = vcpu.SetCpuid(vm.cpuid) 116 | if err != nil { 117 | vcpu.Dispose() 118 | return nil, err 119 | } 120 | 121 | // Return our VCPU object. 122 | return vcpu, vcpu.initRunInfo() 123 | } 124 | 125 | func (vcpu *Vcpu) Dispose() error { 126 | 127 | // Halt the processor. 128 | err := vcpu.SetMpState(MpStateHalted) 129 | if err != nil { 130 | return err 131 | } 132 | 133 | // Cleanup our resources. 134 | syscall.Munmap(vcpu.mmap) 135 | return syscall.Close(vcpu.fd) 136 | } 137 | 138 | func (vcpu *Vcpu) SetStepping(step bool) error { 139 | 140 | var guest_debug C.struct_kvm_guest_debug 141 | 142 | if step == vcpu.is_stepping { 143 | // Already set. 144 | return nil 145 | } else if step { 146 | guest_debug.control = C.__u32(C.IoctlGuestDebugEnable) 147 | } else { 148 | guest_debug.control = 0 149 | } 150 | 151 | // Execute our debug ioctl. 152 | _, _, e := syscall.Syscall( 153 | syscall.SYS_IOCTL, 154 | uintptr(vcpu.fd), 155 | uintptr(C.IoctlSetGuestDebug), 156 | uintptr(unsafe.Pointer(&guest_debug))) 157 | if e != 0 { 158 | return e 159 | } 160 | 161 | // We're okay. 162 | vcpu.is_stepping = step 163 | return nil 164 | } 165 | 166 | func (vcpu *Vcpu) IsStepping() bool { 167 | return vcpu.is_stepping 168 | } 169 | -------------------------------------------------------------------------------- /src/novmm/platform/kvm_xcrs.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package platform 16 | 17 | /* 18 | #include 19 | 20 | // IOCTL calls. 21 | const int IoctlGetXcrs = KVM_GET_XCRS; 22 | const int IoctlSetXcrs = KVM_SET_XCRS; 23 | */ 24 | import "C" 25 | 26 | import ( 27 | "syscall" 28 | "unsafe" 29 | ) 30 | 31 | // 32 | // A single XCR. 33 | // 34 | type Xcr struct { 35 | Id uint32 `json:"xcr"` 36 | Value uint64 `json:"value"` 37 | } 38 | 39 | func (vcpu *Vcpu) GetXcrs() ([]Xcr, error) { 40 | 41 | // Execute the ioctl. 42 | var kvm_xcrs C.struct_kvm_xcrs 43 | _, _, e := syscall.Syscall( 44 | syscall.SYS_IOCTL, 45 | uintptr(vcpu.fd), 46 | uintptr(C.IoctlGetXcrs), 47 | uintptr(unsafe.Pointer(&kvm_xcrs))) 48 | if e != 0 { 49 | return nil, e 50 | } 51 | 52 | // Build our list. 53 | xcrs := make([]Xcr, 0, kvm_xcrs.nr_xcrs) 54 | for i := 0; i < int(kvm_xcrs.nr_xcrs); i += 1 { 55 | xcrs = append(xcrs, Xcr{ 56 | Id: uint32(kvm_xcrs.xcrs[i].xcr), 57 | Value: uint64(kvm_xcrs.xcrs[i].value), 58 | }) 59 | } 60 | 61 | return xcrs, nil 62 | } 63 | 64 | func (vcpu *Vcpu) SetXcrs(xcrs []Xcr) error { 65 | 66 | // Build our parameter. 67 | var kvm_xcrs C.struct_kvm_xcrs 68 | kvm_xcrs.nr_xcrs = C.__u32(len(xcrs)) 69 | for i, xcr := range xcrs { 70 | kvm_xcrs.xcrs[i].xcr = C.__u32(xcr.Id) 71 | kvm_xcrs.xcrs[i].value = C.__u64(xcr.Value) 72 | } 73 | 74 | // Execute the ioctl. 75 | _, _, e := syscall.Syscall( 76 | syscall.SYS_IOCTL, 77 | uintptr(vcpu.fd), 78 | uintptr(C.IoctlSetXcrs), 79 | uintptr(unsafe.Pointer(&kvm_xcrs))) 80 | if e != 0 { 81 | return e 82 | } 83 | 84 | return nil 85 | } 86 | -------------------------------------------------------------------------------- /src/novmm/platform/kvm_xsave.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package platform 16 | 17 | /* 18 | #include 19 | 20 | // IOCTL calls. 21 | const int IoctlGetXSave = KVM_GET_XSAVE; 22 | const int IoctlSetXSave = KVM_SET_XSAVE; 23 | */ 24 | import "C" 25 | 26 | import ( 27 | "syscall" 28 | "unsafe" 29 | ) 30 | 31 | // 32 | // Our xsave state. 33 | // 34 | type XSave struct { 35 | Region [1024]uint32 `json:"region"` 36 | } 37 | 38 | func (vcpu *Vcpu) GetXSave() (XSave, error) { 39 | 40 | // Execute the ioctl. 41 | var kvm_xsave C.struct_kvm_xsave 42 | _, _, e := syscall.Syscall( 43 | syscall.SYS_IOCTL, 44 | uintptr(vcpu.fd), 45 | uintptr(C.IoctlGetXSave), 46 | uintptr(unsafe.Pointer(&kvm_xsave))) 47 | if e != 0 { 48 | return XSave{}, e 49 | } 50 | 51 | state := XSave{} 52 | for i := 0; i < len(state.Region); i += 1 { 53 | state.Region[i] = uint32(kvm_xsave.region[i]) 54 | } 55 | 56 | return state, nil 57 | } 58 | 59 | func (vcpu *Vcpu) SetXSave(state XSave) error { 60 | 61 | // Execute the ioctl. 62 | var kvm_xsave C.struct_kvm_xsave 63 | for i := 0; i < len(state.Region); i += 1 { 64 | kvm_xsave.region[i] = C.__u32(state.Region[i]) 65 | } 66 | _, _, e := syscall.Syscall( 67 | syscall.SYS_IOCTL, 68 | uintptr(vcpu.fd), 69 | uintptr(C.IoctlSetXSave), 70 | uintptr(unsafe.Pointer(&kvm_xsave))) 71 | if e != 0 { 72 | return e 73 | } 74 | 75 | return nil 76 | } 77 | -------------------------------------------------------------------------------- /src/novmm/platform/types.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package platform 16 | 17 | // Basic abstractions. 18 | type Irq uint32 19 | 20 | // Address types. 21 | type Vaddr uint64 22 | type Paddr uint64 23 | 24 | func Align(addr uint64, alignment uint, up bool) uint64 { 25 | 26 | // Aligned already? 27 | if addr%uint64(alignment) == 0 { 28 | return addr 29 | } 30 | 31 | // Give the closest aligned address. 32 | addr = addr - (addr % uint64(alignment)) 33 | 34 | if up { 35 | // Should we align up? 36 | return addr + uint64(alignment) 37 | } 38 | return addr 39 | } 40 | 41 | func (paddr Paddr) Align(alignment uint, up bool) Paddr { 42 | return Paddr(Align(uint64(paddr), alignment, up)) 43 | } 44 | 45 | func (paddr Paddr) OffsetFrom(base Paddr) uint64 { 46 | return uint64(paddr) - uint64(base) 47 | } 48 | 49 | func (paddr Paddr) After(length uint64) Paddr { 50 | return Paddr(uint64(paddr) + uint64(length)) 51 | } 52 | -------------------------------------------------------------------------------- /src/novmm/platform/utils.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package platform 16 | 17 | import ( 18 | "unsafe" 19 | ) 20 | 21 | func AlignBytes(data []byte) []byte { 22 | if uintptr(unsafe.Pointer(&data[0]))%PageSize != 0 { 23 | orig_data := data 24 | data = make([]byte, len(orig_data), len(orig_data)) 25 | copy(data, orig_data) 26 | } 27 | return data 28 | } 29 | -------------------------------------------------------------------------------- /src/novmm/utils/decoder.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package utils 16 | 17 | import ( 18 | "encoding/json" 19 | "io" 20 | ) 21 | 22 | func NewDecoder(reader io.Reader) *json.Decoder { 23 | decoder := json.NewDecoder(reader) 24 | decoder.UseNumber() 25 | return decoder 26 | } 27 | -------------------------------------------------------------------------------- /src/novmm/utils/die.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package utils 16 | 17 | import ( 18 | "log" 19 | ) 20 | 21 | func Die(err error) { 22 | log.Fatal(err) 23 | } 24 | -------------------------------------------------------------------------------- /src/novmm/utils/encoder.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package utils 16 | 17 | import ( 18 | "encoding/json" 19 | "io" 20 | ) 21 | 22 | func NewEncoder(writer io.Writer) *json.Encoder { 23 | encoder := json.NewEncoder(writer) 24 | return encoder 25 | } 26 | -------------------------------------------------------------------------------- /src/novmm/utils/signals.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package utils 16 | 17 | import ( 18 | "syscall" 19 | ) 20 | 21 | const ( 22 | SigVcpuInt = syscall.SIGUSR1 23 | SigShutdown = syscall.SIGTERM 24 | SigRestart = syscall.SIGHUP 25 | SigSpecialRestart = syscall.SIGUSR2 26 | ) 27 | --------------------------------------------------------------------------------