Merge pull request #1625 from jcvenegas/topic/clear-containers-project

projects: Add clear containers project
This commit is contained in:
Justin Cormack 2017-04-14 07:28:07 -05:00 committed by GitHub
commit a752a3263f
14 changed files with 5324 additions and 1 deletions

View File

@ -18,8 +18,8 @@ If you want to create a project, please submit a pull request to create a new di
- [AWS](aws/) AWS build support
- [Swarmd](swarmd) Standalone swarmkit based orchestrator
- [Landlock LSM](landlock/) programmatic access control
- [Clear Containers](clear-containers/) Clear Containers image
## Current projects not yet documented
- Clear Linux integration (Intel)
- VMWare support (VMWare)
- ARM port and secure boot integration (ARM)

View File

@ -0,0 +1,104 @@
# Clear Containers image #
This project's goal is to use LinuxKit\* to generate two components for the
Clear Containers project:
- Kernel: The Linux\* kernel for Intel® Clear Containers following LinuxKit
philosophy.
- Image or mini-os: the minimal guest user-space image (The guest OS based in
LinuxKit is not functional for clear-containers yet).
## What are Clear Containers? ##
Intel® Clear Containers are a collection of tools, configurations, and
techniques anchored on an implementation leveraging Intel® Architecture to
optimize hypervisor-based containers. Intel® Clear Containers enable a small
virtual machine with the isolation of virtual-machine technology along with
the deployment benefits of containers.
Today, the Intel® Clear Containers project uses a Clear Linux\* OS for Intel®
Architecture based guest OS image. The Clear Linux based image provides:
- [systemd]
- [hyperstart]
## Why use LinuxKit to build a Clear Containers guest OS?##
Using LinuxKit to build the guest OS fits the Clear Containers guest needs. LinuxKit
provides:
- An immutable Linux distribution: Write operations from the guest to the
file system are not persistent.
- Easy tooling with easy iteration.
- A general purpose toolkit.
## Current development status ##
A Clear Containers compatible kernel can be generated using LinuxKit
which has the security features of LinuxKit and the virtualization
features required by Clear Containers.
## Getting started ##
To build the kernel, enter the following commands:
1. Build kernel
This step is required to build a kernel from source
It will use the kernel configuration file:
`projects/clear-containers/kernel/kernel_config` and
the patches from `projects/clear-containers/kernel/patches-*`
NOTE: This step also is needed meanwhile an image
`linuxkit/kernel-clear-containers:X.y.x `is pushed to docker-hub.
The following commands will build a kernel using
`projects/clear-containers/kernel/Dockerfile` :
```
pushd projects/clear-containers/kernel
make image
make tag
popd
```
2. Get a Clear Containers kernel using moby tool
To generate the kernel image called `clear-containers-bzImage`, enter the
following command:
```
./bin/moby build ./projects/clear-containers/clear-containers.yml
```
3. Test kernel
The Makefile target `qemu-lite` from `projects/clear-containers/tools`
will launch the Clear Containers base OS and the
with kernel built with moby. Use the `root` user to access to the test system,
it will ask to setup a password.
```
cd projects/clear-containers/tools
make qemu-lite
```
The file `clear-containers-bzImage` is not a bzImage\*. The file
is a vmlinux image, see TODO. The [cc-oci-runtime] project can be
configured to use kernel generated by LinuxKit.
## TODO ##
* Create a Clear Container Mini-OS image.
* Start `hyperstart` as a privileged container.
* Add a script to launch a clear container guest.
* Sync with official kernel LinuxKit patches.
* Add an output format similar to `kernel+initrd` which extracts a vmlinux
image. The Intel® Clear Containers project requires an uncompressed kernel
to boot. Currently, the LinuxKit output format `kernel+initrd` extracts a
bzImage from a LinuxKit packaged kernel. A way to extract the vmlinux image is
still required.
[systemd]: <https://www.freedesktop.org/wiki/Software/systemd/>
[hyperstart]: <https://github.com/clearcontainers/hyperstart>
[cc-oci-runtime]: <https://github.com/01org/cc-oci-runtime>
[hyperstart container]: <https://github.com/clearcontainers/hyperstart/tree/0.7.0-clearcontainers>

View File

@ -0,0 +1,26 @@
kernel:
image: "linuxkit/kernel-clear-containers:4.9.x"
cmdline: "root=/dev/pmem0p1 rootflags=dax,data=ordered,errors=remount-ro rw rootfstype=ext4 tsc=reliable no_timer_check rcupdate.rcu_expedited=1 i8042.direct=1 i8042.dumbkbd=1 i8042.nopnp=1 i8042.noaux=1 noreplace-smp reboot=k panic=1 console=hvc0 console=hvc1 initcall_debug iommu=off quiet cryptomgr.notests page_poison=on"
init:
- mobylinux/init:8375addb923b8b88b2209740309c92aa5f2a4f9d
onboot:
- name: sysctl
image: "mobylinux/sysctl:2cf2f9d5b4d314ba1bfc22b2fe931924af666d8c"
net: host
pid: host
ipc: host
capabilities:
- CAP_SYS_ADMIN
readonly: true
services:
- name: rngd
image: "mobylinux/rngd:3dad6dd43270fa632ac031e99d1947f20b22eec9"
capabilities:
- CAP_SYS_ADMIN
oomScoreAdj: -800
readonly: true
files:
- path: etc/docker/daemon.json
contents: '{"debug": true}'
outputs:
- format: kernel+initrd

View File

@ -0,0 +1,64 @@
FROM linuxkit/alpine-build-kernel:cfdd576c36a52ed2dd62f237f79eeedc2dd3697b@sha256:3fe08db373a9373ba1616a485858f01ebd2d7a3cb364a099d0ed8b45fa419da2
ARG KERNEL_VERSION
ARG DEBUG=0
ENV KERNEL_SOURCE=https://www.kernel.org/pub/linux/kernel/v4.x/linux-${KERNEL_VERSION}.tar.xz
# Download kernel source code
RUN curl -fsSL -o linux-${KERNEL_VERSION}.tar.xz ${KERNEL_SOURCE}
RUN tar xf linux-${KERNEL_VERSION}.tar.xz && mv /linux-${KERNEL_VERSION} /linux
WORKDIR /linux
ENV DEF_CONFIG_FILE=/linux/arch/x86/configs/x86_64_defconfig
COPY kernel_config ${DEF_CONFIG_FILE}
COPY kernel_config.debug /linux/debug_config
# Enable debug
RUN if [ $DEBUG -ne "0" ]; then \
sed -i 's/CONFIG_PANIC_ON_OOPS=y/# CONFIG_PANIC_ON_OOPS is not set/' \
${DEF_CONFIG_FILE}; \
cat /linux/debug_config >> ${DEF_CONFIG_FILE}; \
fi
RUN cat ${DEF_CONFIG_FILE}
# Apply local patches
COPY patches-4.9 /patches
RUN cd /linux && \
set -e && for patch in /patches/*.patch; do \
echo "Applying $patch"; \
patch -p1 < "$patch"; \
done
# Build kernel
RUN make defconfig && \
make oldconfig && \
perl -p -i -e "s/^EXTRAVERSION.*/EXTRAVERSION = -linuxkit/" Makefile && \
make -j "$(getconf _NPROCESSORS_ONLN)" KCFLAGS="-fno-pie"
#bzImage
#vmlinux
RUN cp vmlinux arch/x86_64/boot/bzImage /
# CC does not provide modules, not needed to distribute headers.
#kernel-headers.tar: provides kernel headers
RUN mkdir -p /tmp/kernel-headers/usr && \
cd /tmp/kernel-headers && tar cf /kernel-headers.tar usr
# CC does no use modules do not ship it
#kernel-modules.tar: provides kernel modules
RUN mkdir -p /tmp/kernel-modules/lib/modules && \
cd /tmp/kernel-modules && tar cf /kernel-modules.tar lib
WORKDIR /
#kernel-dev.tar: provides headers .config linux/include arch/x86/include
RUN mkdir -p /tmp/usr/src/linux-headers && \
cd /tmp/ && tar cf /kernel-dev.tar usr/src
RUN printf "KERNEL_SOURCE=${KERNEL_SOURCE}\n" > /kernel-source-info

View File

@ -0,0 +1,87 @@
DEBUG ?= 0
all: vmlinux push
# We push the image to hub twice, once with the full kernel version of
# "linuxkit/kernel:<kernel version>.<major version>.<minor version>-<n>",
# where "<n>" is a monotonically increasing config number, and as
# "linuxkit/kernel:<kernel version>.<major version>.x". This version
# number is stored in IMAGE_VERSION.
#
# We expect most users to us the "<kernel version>.<major version>.x"
# variant as this simply is the latest version of a given major kernel
# version. This version number is stored in IMAGE_MAJOR_VERSION.
#
# For IMAGE_VERSION, the "<n>" must be increased whenever
# the kernel config or the patches change. We don't expect this to
# happen very often as the minor version number gets update quite
# frequently.
#
# IMAGE_VERSION is used to determine if a new image should be pushed to hub.
KERNEL_VERSION=4.9.22
IMAGE_VERSION=$(KERNEL_VERSION)-0
IMAGE_MAJOR_VERSION=4.9.x
DEPS=Dockerfile Makefile kernel_config kernel_config.debug patches-4.9
PKG_DEPS=bzImage kernel-dev.tar kernel-headers.tar vmlinux kernel-modules.tar
ifdef http_proxy
BUILD_PROXY = --build-arg http_proxy=$(http_proxy)
RUN_PROXY = --env http_proxy=$(http_proxy)
endif
ifdef https_proxy
BUILD_PROXY += --build-arg https_proxy=$(https_proxy)
RUN_PROXY += --env https_proxy=$(https_proxy)
endif
#build a kernel using dockerfile and save image hash in kernel.tag
kernel.tag: $(DEPS)
BUILD=$$( tar cf - $^ | docker build -f $< $(BUILD_PROXY) --build-arg DEBUG=$(DEBUG) --build-arg KERNEL_VERSION=$(KERNEL_VERSION) -q - ) && [ -n "$$BUILD" ] && echo "Built $$BUILD" && echo "$$BUILD" > $@
#Extract $(PKG) from image with built kernel
vmlinux: kernel.tag
mkdir -p x86_64
docker run --rm --net=none --log-driver=none \
$(shell cat kernel.tag) \
tar cf - $(PKG_DEPS) | tar xf - -C x86_64
cp x86_64/kernel-modules.tar kernel.tar
# FIXME: Remove when linuxkit allow get vmlinux from docker images
# Rename vmlinux to bzImage
cp x86_64/vmlinux bzImage
cp x86_64/vmlinux $@
.PHONY: image push tag
MEDIA_TOYBOX=linuxkit/toybox-media:d7e82a7d19ccc84c9071fa7a88ecaa58ae958f7c@sha256:4c7d25f2be2429cd08417c36e04161cb924e46f3e419ee33a0aa9ff3a0942e02
BASE="$MEDIA_TOYBOX"
IMAGE=kernel-clear-containers
default: push
Dockerfile.media:
printf "FROM $(MEDIA_TOYBOX)\nADD . /\n" > $@
image: Dockerfile.media vmlinux bzImage kernel.tar $(DEPS)
tar cf - $^ | docker build --no-cache -t $(IMAGE):build -f Dockerfile.media -
push: image
docker pull linuxkit/$(IMAGE):$(IMAGE_VERSION) || \
(docker tag $(IMAGE):build linuxkit/$(IMAGE):$(IMAGE_VERSION) && \
docker push linuxkit/$(IMAGE):$(IMAGE_VERSION) && \
docker tag $(IMAGE):build linuxkit/$(IMAGE):$(IMAGE_MAJOR_VERSION) && \
docker push linuxkit/$(IMAGE):$(IMAGE_MAJOR_VERSION))
docker rmi $(IMAGE):build
rm -f hash
tag: image
(docker tag $(IMAGE):build linuxkit/$(IMAGE):$(IMAGE_VERSION) && \
docker tag $(IMAGE):build linuxkit/$(IMAGE):$(IMAGE_MAJOR_VERSION))
docker rmi $(IMAGE):build
rm -f hash
.PHONY: clean
clean:
rm -rf x86_64 lib usr sbin kernel.tag Dockerfile.media vmlinux bzImage kernel.tar etc
.DELETE_ON_ERROR:

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,34 @@
From ae8bbac0d97941a8d54451c98479dc14dddf9678 Mon Sep 17 00:00:00 2001
From: Arjan van de Ven <arjan@linux.intel.com>
Date: Wed, 11 Feb 2015 16:19:26 -0600
Subject: [PATCH 1/4] cpuidle: skip synchronize_rcu() on single CPU systems
synchronize_rcu() is pretty expensive, and on single CPU systems we don't need
it in this specific case, so skip it.
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
Signed-off-by: Miguel Bernal Marin <miguel.bernal.marin@linux.intel.com>
---
drivers/cpuidle/cpuidle.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index c73207ab..224cefc0 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -307,8 +307,11 @@ void cpuidle_uninstall_idle_handler(void)
/*
* Make sure external observers (such as the scheduler)
* are done looking at pointed idle states.
+ * This is only relevant if there is more than one cpu,
+ * if there is only one CPU, that is us... and we're
+ * coherent to ourselves.
*/
- synchronize_rcu();
+
}
/**
--
2.12.2

View File

@ -0,0 +1,38 @@
From e1b22ee1b1a8160cb03112d89defd9bf8ae8baf1 Mon Sep 17 00:00:00 2001
From: Arjan van de Ven <arjan@linux.intel.com>
Date: Wed, 11 Feb 2015 16:25:16 -0600
Subject: [PATCH 2/4] sysrq: skip synchronize_rcu() if there is no old op
synchronize_rcu() is expensive. Currently it is called as part of the sysrq
registration/unregistration, which happens during boot several times.
Now, the reason for the synchronize_rcu() is to allow an old registered
operation to expire properly... which is pointless if the old operation
is NULL...
So we can save the common case of the old operation being NULL a lot of time
by just checking for non-NULL prior to the synchronize_rcu()
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
Signed-off-by: Miguel Bernal Marin <miguel.bernal.marin@linux.intel.com>
---
drivers/tty/sysrq.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index 701c085b..c60c7ba5 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -1065,8 +1065,10 @@ static int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p,
* A concurrent __handle_sysrq either got the old op or the new op.
* Wait for it to go away before returning, so the code for an old
* op is not freed (eg. on module unload) while it is in use.
+ * This is only relevant if the old op is not NULL of course.
*/
- synchronize_rcu();
+ if (remove_op_p)
+ synchronize_rcu();
return retval;
}
--
2.12.2

View File

@ -0,0 +1,39 @@
From 58736c7e70371aa602e284812d493108b25070c3 Mon Sep 17 00:00:00 2001
From: Arjan van de Ven <arjan@linux.intel.com>
Date: Mon, 22 Jun 2015 09:33:33 -0500
Subject: [PATCH 3/4] init: no wait for the known devices
No wait for the known devices to complete their probing
Author: Arjan van de Ven <arjan@linux.intel.com>
Signed-off-by: Miguel Bernal Marin <miguel.bernal.marin@linux.intel.com>
---
init/do_mounts.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/init/do_mounts.c b/init/do_mounts.c
index dea5de95..da840946 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -28,6 +28,7 @@
#include <linux/slab.h>
#include <linux/ramfs.h>
#include <linux/shmem_fs.h>
+#include <linux/async.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_fs_sb.h>
@@ -563,7 +564,8 @@ void __init prepare_namespace(void)
* For example, it is not atypical to wait 5 seconds here
* for the touchpad of a laptop to initialize.
*/
- wait_for_device_probe();
+ //wait_for_device_probe();
+ async_synchronize_full();
md_run_setup();
--
2.12.2

View File

@ -0,0 +1,131 @@
From 627247f7d57ce964617f6580d9c5e1184850ac5d Mon Sep 17 00:00:00 2001
From: Eric Van Hensbergen <ericvh@gmail.com>
Date: Tue, 21 Apr 2015 12:46:29 -0700
Subject: [PATCH 4/4] fs/9p: fix create-unlink-getattr idiom
Fixes several outstanding bug reports of not being able to getattr from an
open file after an unlink. This patch cleans up transient fids on an unlink
and will search open fids on a client if it detects a dentry that appears to
have been unlinked. This search is necessary because fstat does not pass fd
information through the VFS API to the filesystem, only the dentry which for
9p has an imperfect match to fids.
Inherent in this patch is also a fix for the qid handling on create/open
which apparently wasn't being set correctly and was necessary for the search
to succeed.
A possible optimization over this fix is to include accounting of open fids
with the inode in the private data (in a similar fashion to the way we track
transient fids with dentries). This would allow a much quicker search for
a matching open fid.
Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com>
---
fs/9p/fid.c | 30 ++++++++++++++++++++++++++++++
fs/9p/vfs_inode.c | 4 ++++
net/9p/client.c | 5 ++++-
3 files changed, 38 insertions(+), 1 deletion(-)
diff --git a/fs/9p/fid.c b/fs/9p/fid.c
index 60fb4746..e19c9cf7 100644
--- a/fs/9p/fid.c
+++ b/fs/9p/fid.c
@@ -54,6 +54,33 @@ void v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid)
}
/**
+ * v9fs_fid_find_global - search for a fid off of the client list
+ * @inode: return a fid pointing to a specific inode
+ * @uid: return a fid belonging to the specified user
+ *
+ */
+
+static struct p9_fid *v9fs_fid_find_inode(struct inode *inode, kuid_t uid)
+{
+ struct p9_client *clnt = v9fs_inode2v9ses(inode)->clnt;
+ struct p9_fid *fid, *fidptr, *ret = NULL;
+ unsigned long flags;
+
+ p9_debug(P9_DEBUG_VFS, " inode: %p\n", inode);
+
+ spin_lock_irqsave(&clnt->lock, flags);
+ list_for_each_entry_safe(fid, fidptr, &clnt->fidlist, flist) {
+ if (uid_eq(fid->uid, uid) &&
+ (inode->i_ino == v9fs_qid2ino(&fid->qid))) {
+ ret = fid;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&clnt->lock, flags);
+ return ret;
+}
+
+/**
* v9fs_fid_find - retrieve a fid that belongs to the specified uid
* @dentry: dentry to look for fid in
* @uid: return fid that belongs to the specified user
@@ -80,6 +107,9 @@ static struct p9_fid *v9fs_fid_find(struct dentry *dentry, kuid_t uid, int any)
}
}
spin_unlock(&dentry->d_lock);
+ } else {
+ if (dentry->d_inode)
+ ret = v9fs_fid_find_inode(dentry->d_inode, uid);
}
return ret;
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 30ca770c..c00487ea 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -624,6 +624,10 @@ static int v9fs_remove(struct inode *dir, struct dentry *dentry, int flags)
v9fs_invalidate_inode_attr(inode);
v9fs_invalidate_inode_attr(dir);
+
+ /* invalidate all fids associated with dentry */
+ /* NOTE: This will not include open fids */
+ dentry->d_op->d_release(dentry);
}
return retval;
}
diff --git a/net/9p/client.c b/net/9p/client.c
index 3fc94a49..98980bac 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -1208,7 +1208,7 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, uint16_t nwname,
if (nwname)
memmove(&fid->qid, &wqids[nwqids - 1], sizeof(struct p9_qid));
else
- fid->qid = oldfid->qid;
+ memmove(&fid->qid, &oldfid->qid, sizeof(struct p9_qid));
kfree(wqids);
return fid;
@@ -1261,6 +1261,7 @@ int p9_client_open(struct p9_fid *fid, int mode)
p9_is_proto_dotl(clnt) ? "RLOPEN" : "ROPEN", qid.type,
(unsigned long long)qid.path, qid.version, iounit);
+ memmove(&fid->qid, &qid, sizeof(struct p9_qid));
fid->mode = mode;
fid->iounit = iounit;
@@ -1306,6 +1307,7 @@ int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode,
(unsigned long long)qid->path,
qid->version, iounit);
+ memmove(&ofid->qid, qid, sizeof(struct p9_qid));
ofid->mode = mode;
ofid->iounit = iounit;
@@ -1351,6 +1353,7 @@ int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
(unsigned long long)qid.path,
qid.version, iounit);
+ memmove(&fid->qid, &qid, sizeof(struct p9_qid));
fid->mode = mode;
fid->iounit = iounit;
--
2.12.2

View File

@ -0,0 +1,10 @@
FROM fedora:25
RUN dnf install -y 'dnf-command(config-manager)'
RUN dnf config-manager --add-repo \
http://download.opensuse.org/repositories/home:clearlinux:preview:clear-containers-2.1/Fedora\_25/home:clearlinux:preview:clear-containers-2.1.repo
RUN dnf install -y qemu-lite clear-containers-image linux-container
COPY qemu.sh /bin/qemu.sh
WORKDIR /root
ENTRYPOINT ["qemu.sh"]

View File

@ -0,0 +1,35 @@
MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
MKFILE_DIR := $(dir $(MKFILE_PATH))
ifdef http_proxy
BUILD_PROXY = --build-arg http_proxy=$(http_proxy)
RUN_PROXY = --env http_proxy=$(http_proxy)
endif
ifdef https_proxy
BUILD_PROXY += --build-arg https_proxy=$(https_proxy)
RUN_PROXY += --env https_proxy=$(https_proxy)
endif
CMDLINE_FILE=clear-containers-cmdline
KERNEL_FILE=clear-containers-bzImage
IMAGE=qemu-lite
docker_image: Dockerfile
docker build $(BUILD_PROXY) -t clearcontainers/$(IMAGE) .
qemu-lite: docker_image $(KERNEL_FILE) $(CMDLINE_FILE)
docker run --privileged --rm -ti \
-v $$(pwd)/$(CMDLINE_FILE):/root/clear-containers-cmdline \
-v $$(pwd)/$(KERNEL_FILE):/root/clear-containers-vmlinux \
clearcontainers/$(IMAGE) \
bash
$(KERNEL_FILE):
$(MKFILE_DIR)/../../../bin/moby build $(MKFILE_DIR)/../clear-containers.yml
push: docker_image
docker push clearcontainers/$(IMAGE)
clean:
rm -rf *-bzImage *-cmdline *.img

View File

@ -0,0 +1,49 @@
#!/bin/bash
set -e
function die {
echo >&2 "$@"
exit 1
}
img=/usr/share/clear-containers/clear-containers.img
img=$(readlink -f "$img")
img_size=$(du -b "${img}" | awk '{print $1}')
kernel="$(pwd)/clear-containers-vmlinux"
kernel_cmdline_file="$(pwd)/clear-containers-cmdline"
[ -f "${img}" ] || die "Image s required"
[ -f "${kernel}" ] || die "Kernel is required"
[ -f ${kernel_cmdline_file} ] || \
die "Kernel cmdline file is required"
kernel_cmdline=$(cat "$kernel_cmdline_file")
cmd="/usr/bin/qemu-lite-system-x86_64"
cmd="$cmd -machine pc-lite,accel=kvm,kernel_irqchip,nvdimm"
cmd="$cmd -device nvdimm,memdev=mem0,id=nv0"
#image
cmd="$cmd -object memory-backend-file,id=mem0,mem-path=${img},size=${img_size}"
#memory
cmd="$cmd -m 2G,slots=2,maxmem=3G"
#kernel
cmd="$cmd -kernel ${kernel}"
cmd="$cmd -append '${kernel_cmdline}'"
#cpu
cmd="$cmd -smp 2,sockets=1,cores=2,threads=1"
cmd="$cmd -cpu host"
#clock
cmd="$cmd -rtc base=utc,driftfix=slew"
cmd="$cmd -no-user-config"
cmd="$cmd -nodefaults"
cmd="$cmd -global"
cmd="$cmd kvm-pit.lost_tick_policy=discard"
#console
cmd="$cmd -device virtio-serial-pci,id=virtio-serial0"
cmd="$cmd -chardev stdio,id=charconsole0,signal=off"
cmd="$cmd -device virtconsole,chardev=charconsole0,id=console0"
cmd="$cmd -nographic"
cmd="$cmd -vga none"
eval "$cmd"