Merge branch 'hvm' of 10.141.1.101:/var/lib/qubes/git/marmarek/core
This commit is contained in:
commit
859c99da5c
32
dom0/misc/vm-template-hvm.conf
Normal file
32
dom0/misc/vm-template-hvm.conf
Normal file
@ -0,0 +1,32 @@
|
||||
#
|
||||
# This is a Xen VM config file for Qubes VM
|
||||
# DO NOT EDIT - autogenerated by qubes tools
|
||||
#
|
||||
|
||||
name = "{name}"
|
||||
|
||||
builder='hvm'
|
||||
memory={mem}
|
||||
viridian=1
|
||||
kernel='hvmloader'
|
||||
#acpi=1
|
||||
#apic=1
|
||||
boot='dca'
|
||||
device_model='stubdom-dm'
|
||||
#pae=1
|
||||
usbdevice='tablet'
|
||||
sdl=0
|
||||
vnc=0
|
||||
disk = [ {rootdev}
|
||||
{otherdevs}
|
||||
]
|
||||
vif = [ {netdev} ]
|
||||
pci = [ {pcidev} ]
|
||||
vcpus = {vcpus}
|
||||
|
||||
#tsc_mode = 2
|
||||
#xen_extended_power_mgmt=0
|
||||
|
||||
on_poweroff = 'destroy'
|
||||
on_reboot = 'destroy'
|
||||
on_crash = 'destroy'
|
@ -21,6 +21,7 @@
|
||||
#
|
||||
|
||||
import sys
|
||||
import stat
|
||||
import os
|
||||
import os.path
|
||||
import subprocess
|
||||
@ -78,6 +79,11 @@ default_servicevm_vcpus = 1
|
||||
default_kernelopts = ""
|
||||
default_kernelopts_pcidevs = "iommu=soft swiotlb=2048"
|
||||
|
||||
default_hvm_disk_size = 20*1024*1024*1024
|
||||
|
||||
config_template_pv = '/usr/share/qubes/vm-template.conf'
|
||||
config_template_hvm = '/usr/share/qubes/vm-template-hvm.conf'
|
||||
|
||||
qubes_whitelisted_appmenus = 'whitelisted-appmenus.list'
|
||||
|
||||
dom0_update_check_interval = 6*3600
|
||||
@ -238,6 +244,8 @@ class QubesVm(object):
|
||||
|
||||
self.firewall_conf = self.absolute_path(firewall_conf, default_firewall_conf_file)
|
||||
|
||||
self.config_file_template = config_template_pv
|
||||
|
||||
self.updateable = updateable
|
||||
self._label = label if label is not None else QubesVmLabels["red"]
|
||||
if self.dir_path is not None:
|
||||
@ -788,7 +796,8 @@ class QubesVm(object):
|
||||
def get_config_params(self, source_template=None):
|
||||
args = {}
|
||||
args['name'] = self.name
|
||||
args['kerneldir'] = self.kernels_dir
|
||||
if hasattr(self, 'kernels_dir'):
|
||||
args['kerneldir'] = self.kernels_dir
|
||||
args['vmdir'] = self.dir_path
|
||||
args['pcidev'] = str(self.pcidevs).strip('[]')
|
||||
args['mem'] = str(self.memory)
|
||||
@ -804,11 +813,13 @@ class QubesVm(object):
|
||||
args['rootdev'] = self.get_rootdev(source_template=source_template)
|
||||
args['privatedev'] = "'script:file:{dir}/private.img,xvdb,w',".format(dir=self.dir_path)
|
||||
args['volatiledev'] = "'script:file:{dir}/volatile.img,xvdc,w',".format(dir=self.dir_path)
|
||||
modulesmode='r'
|
||||
if self.is_updateable() and self.kernel is None:
|
||||
modulesmode='w'
|
||||
args['otherdevs'] = "'script:file:{dir}/modules.img,xvdd,{mode}',".format(dir=self.kernels_dir, mode=modulesmode)
|
||||
args['kernelopts'] = self.kernelopts
|
||||
if hasattr(self, 'kernel'):
|
||||
modulesmode='r'
|
||||
if self.is_updateable() and self.kernel is None:
|
||||
modulesmode='w'
|
||||
args['otherdevs'] = "'script:file:{dir}/modules.img,xvdd,{mode}',".format(dir=self.kernels_dir, mode=modulesmode)
|
||||
if hasattr(self, 'kernelopts'):
|
||||
args['kernelopts'] = self.kernelopts
|
||||
|
||||
return args
|
||||
|
||||
@ -818,7 +829,7 @@ class QubesVm(object):
|
||||
if source_template is None:
|
||||
source_template = self.template_vm
|
||||
|
||||
f_conf_template = open('/usr/share/qubes/vm-template.conf', 'r')
|
||||
f_conf_template = open(self.config_file_template, 'r')
|
||||
conf_template = f_conf_template.read()
|
||||
f_conf_template.close()
|
||||
|
||||
@ -1163,6 +1174,14 @@ class QubesVm(object):
|
||||
if notify_function is not None:
|
||||
notify_function("error", "ERROR: Cannot start the Qubes Clipboard Notifier!")
|
||||
|
||||
def start_qrexec_daemon(self, verbose = False):
|
||||
if verbose:
|
||||
print >> sys.stderr, "--> Starting the qrexec daemon..."
|
||||
retcode = subprocess.call ([qrexec_daemon_path, str(xid)])
|
||||
if (retcode != 0) :
|
||||
self.force_shutdown()
|
||||
raise OSError ("ERROR: Cannot execute qrexec_daemon!")
|
||||
|
||||
def start(self, debug_console = False, verbose = False, preparing_dvm = False):
|
||||
if dry_run:
|
||||
return
|
||||
@ -1234,12 +1253,7 @@ class QubesVm(object):
|
||||
qmemman_client.close()
|
||||
|
||||
if not preparing_dvm:
|
||||
if verbose:
|
||||
print >> sys.stderr, "--> Starting the qrexec daemon..."
|
||||
retcode = subprocess.call ([qrexec_daemon_path, str(xid)])
|
||||
if (retcode != 0) :
|
||||
self.force_shutdown()
|
||||
raise OSError ("ERROR: Cannot execute qrexec_daemon!")
|
||||
self.start_qrexec_daemon(verbose=verbose)
|
||||
|
||||
if not preparing_dvm and os.path.exists('/var/run/shm.id'):
|
||||
self.start_guid(verbose=verbose)
|
||||
@ -1285,26 +1299,20 @@ class QubesVm(object):
|
||||
attrs["qid"] = str(self.qid)
|
||||
attrs["name"] = self.name
|
||||
attrs["dir_path"] = self.dir_path
|
||||
attrs["conf_file"] = self.relative_path(self.conf_file)
|
||||
attrs["root_img"] = self.relative_path(self.root_img)
|
||||
attrs["volatile_img"] = self.relative_path(self.volatile_img)
|
||||
attrs["private_img"] = self.relative_path(self.private_img)
|
||||
attrs["uses_default_netvm"] = str(self.uses_default_netvm)
|
||||
# Simple paths
|
||||
for prop in ['conf_file', 'root_img', 'volatile_img', 'private_img']:
|
||||
if hasattr(self, prop):
|
||||
attrs[prop] = self.relative_path(self.__getattribute__(prop))
|
||||
# Simple string attrs
|
||||
for prop in ['memory', 'maxmem', 'pcidevs', 'vcpus', 'internal',\
|
||||
'uses_default_kernel', 'kernel', 'uses_default_kernelopts',\
|
||||
'kernelopts', 'services', 'updateable', 'installed_by_rpm',\
|
||||
'uses_default_netvm' ]:
|
||||
if hasattr(self, prop):
|
||||
attrs[prop] = str(self.__getattribute__(prop))
|
||||
attrs["netvm_qid"] = str(self.netvm_vm.qid) if self.netvm_vm is not None else "none"
|
||||
attrs["installed_by_rpm"] = str(self.installed_by_rpm)
|
||||
attrs["template_qid"] = str(self.template_vm.qid) if self.template_vm and not self.is_updateable() else "none"
|
||||
attrs["updateable"] = str(self.updateable)
|
||||
attrs["label"] = self.label.name
|
||||
attrs["memory"] = str(self.memory)
|
||||
attrs["maxmem"] = str(self.maxmem)
|
||||
attrs["pcidevs"] = str(self.pcidevs)
|
||||
attrs["vcpus"] = str(self.vcpus)
|
||||
attrs["internal"] = str(self.internal)
|
||||
attrs["uses_default_kernel"] = str(self.uses_default_kernel)
|
||||
attrs["kernel"] = str(self.kernel)
|
||||
attrs["uses_default_kernelopts"] = str(self.uses_default_kernelopts)
|
||||
attrs["kernelopts"] = str(self.kernelopts)
|
||||
attrs["services"] = str(self.services)
|
||||
return attrs
|
||||
|
||||
def create_xml_element(self):
|
||||
@ -1988,6 +1996,127 @@ class QubesAppVm(QubesVm):
|
||||
def post_rename(self, old_name):
|
||||
self.create_appmenus(False)
|
||||
|
||||
class QubesHVm(QubesVm):
|
||||
"""
|
||||
A class that represents an HVM. A child of QubesVm.
|
||||
"""
|
||||
|
||||
# FIXME: logically should inherit after QubesAppVm, but none of its methods
|
||||
# are useful for HVM
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
if "dir_path" not in kwargs or kwargs["dir_path"] is None:
|
||||
kwargs["dir_path"] = qubes_appvms_dir + "/" + kwargs["name"]
|
||||
|
||||
super(QubesHVm, self).__init__(**kwargs)
|
||||
self.updateable = True
|
||||
self.config_file_template = config_template_hvm
|
||||
# remove settings not used by HVM (at least for now)
|
||||
self.__delattr__('kernel')
|
||||
self.__delattr__('kernelopts')
|
||||
self.__delattr__('uses_default_kernel')
|
||||
self.__delattr__('uses_default_kernelopts')
|
||||
self.__delattr__('private_img')
|
||||
self.__delattr__('volatile_img')
|
||||
# HVM doesn't support dynamic memory management
|
||||
self.maxmem = self.memory
|
||||
|
||||
self.drive = None
|
||||
if 'drive' in kwargs.keys():
|
||||
self.drive = kwargs['drive']
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return "HVM"
|
||||
|
||||
def is_appvm(self):
|
||||
return True
|
||||
|
||||
def create_on_disk(self, verbose, source_template = None):
|
||||
if dry_run:
|
||||
return
|
||||
|
||||
if verbose:
|
||||
print >> sys.stderr, "--> Creating directory: {0}".format(self.dir_path)
|
||||
os.mkdir (self.dir_path)
|
||||
|
||||
self.create_config_file()
|
||||
|
||||
# create empty disk
|
||||
f_root = open(self.root_img, "w")
|
||||
f_root.truncate(default_hvm_disk_size)
|
||||
f_root.close()
|
||||
|
||||
|
||||
def get_disk_utilization_private_img(self):
|
||||
return 0
|
||||
|
||||
def get_private_img_sz(self):
|
||||
return 0
|
||||
|
||||
def resize_private_img(self, size):
|
||||
raise NotImplementedError("HVM has no private.img")
|
||||
|
||||
def get_config_params(self, source_template=None):
|
||||
|
||||
params = super(QubesHVm, self).get_config_params(source_template=source_template)
|
||||
|
||||
params['volatiledev'] = ''
|
||||
params['privatedev'] = ''
|
||||
if self.drive:
|
||||
stat_res = os.stat(self.drive)
|
||||
if stat.S_ISBLK(stat_res.st_mode):
|
||||
params['otherdevs'] = "'phy:%s,hdc:cdrom,r'," % self.drive
|
||||
else:
|
||||
params['otherdevs'] = "'script:file:%s,hdc:cdrom,r'," % self.drive
|
||||
else:
|
||||
params['otherdevs'] = ''
|
||||
return params
|
||||
|
||||
def verify_files(self):
|
||||
if dry_run:
|
||||
return
|
||||
|
||||
if not os.path.exists (self.dir_path):
|
||||
raise QubesException (
|
||||
"VM directory doesn't exist: {0}".\
|
||||
format(self.dir_path))
|
||||
|
||||
if self.is_updateable() and not os.path.exists (self.root_img):
|
||||
raise QubesException (
|
||||
"VM root image file doesn't exist: {0}".\
|
||||
format(self.root_img))
|
||||
|
||||
return True
|
||||
|
||||
def reset_volatile_storage(self, **kwargs):
|
||||
pass
|
||||
|
||||
def run(self, command, **kwargs):
|
||||
raise NotImplementedError("Needs qrexec agent - TODO")
|
||||
|
||||
@property
|
||||
def stubdom_xid(self):
|
||||
if not self.is_running():
|
||||
return -1
|
||||
|
||||
return int(xs.read('', '/local/domain/%d/image/device-model-domid' % self.xid))
|
||||
|
||||
def start_guid(self, verbose = True, notify_function = None):
|
||||
if verbose:
|
||||
print >> sys.stderr, "--> Starting Qubes GUId..."
|
||||
|
||||
retcode = subprocess.call ([qubes_guid_path, "-d", str(self.stubdom_xid), "-c", self.label.color, "-i", self.label.icon, "-l", str(self.label.index)])
|
||||
if (retcode != 0) :
|
||||
raise QubesException("Cannot start qubes_guid!")
|
||||
|
||||
def start_qrexec_daemon(self, **kwargs):
|
||||
pass
|
||||
|
||||
def get_xml_attrs(self):
|
||||
attrs = super(QubesHVm, self).get_xml_attrs()
|
||||
attrs["drive"] = str(self.drive)
|
||||
return attrs
|
||||
|
||||
class QubesVmCollection(dict):
|
||||
"""
|
||||
@ -2046,6 +2175,20 @@ class QubesVmCollection(dict):
|
||||
self[vm.qid]=vm
|
||||
return vm
|
||||
|
||||
def add_new_hvm(self, name, label = None):
|
||||
|
||||
qid = self.get_new_unused_qid()
|
||||
vm = QubesHVm (qid=qid, name=name,
|
||||
netvm_vm = self.get_default_netvm_vm(),
|
||||
kernel = self.get_default_kernel(),
|
||||
uses_default_kernel = True,
|
||||
label=label)
|
||||
|
||||
if not self.verify_new_vm (vm):
|
||||
assert False, "Wrong VM description!"
|
||||
self[vm.qid]=vm
|
||||
return vm
|
||||
|
||||
def add_new_disposablevm(self, name, template_vm, dispid,
|
||||
label = None):
|
||||
|
||||
@ -2571,6 +2714,20 @@ class QubesVmCollection(dict):
|
||||
os.path.basename(sys.argv[0]), err))
|
||||
return False
|
||||
|
||||
# And HVMs
|
||||
for element in tree.findall("QubesHVm"):
|
||||
try:
|
||||
kwargs = self.parse_xml_element(element)
|
||||
vm = QubesHVm(**kwargs)
|
||||
|
||||
self[vm.qid] = vm
|
||||
|
||||
self.set_netvm_dependency(element)
|
||||
except (ValueError, LookupError) as err:
|
||||
print("{0}: import error (QubesHVm): {1}".format(
|
||||
os.path.basename(sys.argv[0]), err))
|
||||
return False
|
||||
|
||||
# Really finally, read in the DisposableVMs
|
||||
for element in tree.findall("QubesDisposableVm"):
|
||||
try:
|
||||
|
@ -37,10 +37,14 @@ def main():
|
||||
help="Specify the label to use for the new VM (e.g. red, yellow, green, ...)")
|
||||
parser.add_option ("-p", "--proxy", action="store_true", dest="proxyvm", default=False,
|
||||
help="Create ProxyVM")
|
||||
parser.add_option ("-H", "--hvm", action="store_true", dest="hvm", default=False,
|
||||
help="Create HVM (implies --standalone)")
|
||||
parser.add_option ("-n", "--net", action="store_true", dest="netvm", default=False,
|
||||
help="Create NetVM")
|
||||
parser.add_option ("-s", "--standalone", action="store_true", dest="standalone", default=False,
|
||||
help="Create standalone VM - independent of template ")
|
||||
parser.add_option ("-r", "--root", dest="root", default=None,
|
||||
help="Use provided root.img instead of default/empty one (file will be MOVED)")
|
||||
parser.add_option ("-m", "--mem", dest="mem", default=None,
|
||||
help="Initial memory size (in MB)")
|
||||
parser.add_option ("-c", "--vcpus", dest="vcpus", default=None,
|
||||
@ -82,6 +86,18 @@ def main():
|
||||
exit (1)
|
||||
label = QubesVmLabels[options.label]
|
||||
|
||||
if options.hvm:
|
||||
# Only standalone HVMs are supported for now
|
||||
options.standalone = True
|
||||
|
||||
if not options.standalone and options.root is not None:
|
||||
print >> sys.stderr, "root.img can be specified only for standalone VMs"
|
||||
exit (1)
|
||||
|
||||
if options.root is not None and not os.path.exists(options.root):
|
||||
print >> sys.stderr, "File specified as root.img does not exists"
|
||||
exit (1)
|
||||
|
||||
qvm_collection = QubesVmCollection()
|
||||
qvm_collection.lock_db_for_writing()
|
||||
qvm_collection.load()
|
||||
@ -90,6 +106,7 @@ def main():
|
||||
print >> sys.stderr, "A VM with the name '{0}' already exists in the system.".format(vmname)
|
||||
exit(1)
|
||||
|
||||
template_vm = None
|
||||
if options.template is not None:
|
||||
template_vm = qvm_collection.get_vm_by_name(options.template)
|
||||
if template_vm is None:
|
||||
@ -101,7 +118,7 @@ def main():
|
||||
if (options.verbose):
|
||||
print "--> Using TemplateVM: {0}".format(template_vm.name)
|
||||
|
||||
else:
|
||||
elif not options.hvm:
|
||||
if qvm_collection.get_default_template_vm() is None:
|
||||
print >> sys.stderr, "No default TempleteVM defined!"
|
||||
exit (1)
|
||||
@ -120,6 +137,8 @@ def main():
|
||||
vm = qvm_collection.add_new_netvm(vmname, new_vm_template, label = label, updateable = options.standalone)
|
||||
elif options.proxyvm:
|
||||
vm = qvm_collection.add_new_proxyvm(vmname, new_vm_template, label = label, updateable = options.standalone)
|
||||
elif options.hvm:
|
||||
vm = qvm_collection.add_new_hvm(vmname, label = label)
|
||||
else:
|
||||
vm = qvm_collection.add_new_appvm(vmname, new_vm_template, label = label, updateable = options.standalone)
|
||||
|
||||
@ -134,6 +153,9 @@ def main():
|
||||
|
||||
try:
|
||||
vm.create_on_disk(verbose=options.verbose, source_template=template_vm)
|
||||
if options.root:
|
||||
os.unlink(vm.root_img)
|
||||
os.rename(options.root, vm.root_img)
|
||||
|
||||
except (IOError, OSError) as err:
|
||||
print >> sys.stderr, "ERROR: {0}".format(err)
|
||||
|
@ -51,22 +51,32 @@ def do_list(vm):
|
||||
print fmt.format ("root COW img", vm.rootcow_img)
|
||||
if vm.template_vm is not None:
|
||||
print fmt.format ("root img", vm.template_vm.root_img)
|
||||
print fmt.format ("root volatile img", vm.volatile_img)
|
||||
if hasattr(vm, 'volatile_img'):
|
||||
print fmt.format ("root volatile img", vm.volatile_img)
|
||||
|
||||
print fmt.format ("private img", vm.private_img)
|
||||
if hasattr(vm, 'private_img'):
|
||||
print fmt.format ("private img", vm.private_img)
|
||||
print fmt.format ("vcpus", str(vm.vcpus))
|
||||
print fmt.format ("memory", vm.memory)
|
||||
print fmt.format ("maxmem", vm.maxmem)
|
||||
if vm.template_vm is not None:
|
||||
print fmt.format ("kernel", "%s (from template)" % vm.kernel)
|
||||
elif vm.uses_default_kernel:
|
||||
print fmt.format ("kernel", "%s (default)" % vm.kernel)
|
||||
else:
|
||||
print fmt.format ("kernel", vm.kernel)
|
||||
if vm.uses_default_kernelopts:
|
||||
print fmt.format ("kernelopts", "%s (default)" % vm.kernelopts)
|
||||
else:
|
||||
print fmt.format ("kernelopts", vm.kernelopts)
|
||||
if hasattr(vm, 'maxmem'):
|
||||
print fmt.format ("maxmem", vm.maxmem)
|
||||
|
||||
if hasattr(vm, 'kernel'):
|
||||
if vm.template_vm is not None:
|
||||
print fmt.format ("kernel", "%s (from template)" % vm.kernel)
|
||||
elif vm.uses_default_kernel:
|
||||
print fmt.format ("kernel", "%s (default)" % vm.kernel)
|
||||
else:
|
||||
print fmt.format ("kernel", vm.kernel)
|
||||
|
||||
if hasattr(vm, 'kernelopts'):
|
||||
if vm.uses_default_kernelopts:
|
||||
print fmt.format ("kernelopts", "%s (default)" % vm.kernelopts)
|
||||
else:
|
||||
print fmt.format ("kernelopts", vm.kernelopts)
|
||||
|
||||
if hasattr(vm, 'drive'):
|
||||
print fmt.format("drive", str(vm.drive))
|
||||
|
||||
|
||||
def set_label(vms, vm, args):
|
||||
@ -287,6 +297,13 @@ def set_name(vms, vm, args):
|
||||
vm.set_name(args[0])
|
||||
return True
|
||||
|
||||
def set_drive(vms, vm, args):
|
||||
if len (args) != 1:
|
||||
print >> sys.stderr, "Missing new drive content (file/device)!"
|
||||
return False
|
||||
|
||||
vm.drive = args[0]
|
||||
return True
|
||||
|
||||
properties = {
|
||||
"updateable": set_updateable,
|
||||
@ -301,6 +318,7 @@ properties = {
|
||||
"vcpus" : set_vcpus,
|
||||
"kernelopts": set_kernelopts,
|
||||
"name": set_name,
|
||||
"drive": set_drive,
|
||||
}
|
||||
|
||||
|
||||
@ -309,6 +327,10 @@ def do_set(vms, vm, property, args):
|
||||
print >> sys.stderr, "ERROR: Wrong property name: '{0}'".format(property)
|
||||
return False
|
||||
|
||||
if not hasattr(vm, property):
|
||||
print >> sys.stderr, "ERROR: Property '{0}' not available for this VM".format(property)
|
||||
return False
|
||||
|
||||
return properties[property](vms, vm, args)
|
||||
|
||||
|
||||
@ -353,7 +375,8 @@ def main():
|
||||
print >> sys.stderr, "You must specify the property you wish to set..."
|
||||
print >> sys.stderr, "Available properties:"
|
||||
for p in properties.keys():
|
||||
print >> sys.stderr, "--> '{0}'".format(p)
|
||||
if hasattr(vm, p):
|
||||
print >> sys.stderr, "--> '{0}'".format(p)
|
||||
exit (1)
|
||||
|
||||
property = args[1]
|
||||
|
@ -37,6 +37,8 @@ def main():
|
||||
help="Do not start the GUId (ignored)")
|
||||
parser.add_option ("--console", action="store_true", dest="debug_console", default=False,
|
||||
help="Attach debugging console to the newly started VM")
|
||||
parser.add_option ("--drive", dest="drive", default=None,
|
||||
help="Temporarily attach specified drive as CD/DVD")
|
||||
parser.add_option ("--dvm", action="store_true", dest="preparing_dvm", default=False,
|
||||
help="Do actions necessary when preparing DVM image")
|
||||
|
||||
@ -55,6 +57,13 @@ def main():
|
||||
print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(vmname)
|
||||
exit(1)
|
||||
|
||||
if options.drive:
|
||||
if hasattr(vm, 'drive'):
|
||||
vm.drive = options.drive
|
||||
else:
|
||||
print >> sys.stderr, "This VM does not support attaching drives"
|
||||
exit (1)
|
||||
|
||||
try:
|
||||
vm.verify_files()
|
||||
xid = vm.start(debug_console=options.debug_console, verbose=options.verbose, preparing_dvm=options.preparing_dvm)
|
||||
|
@ -151,6 +151,7 @@ cp misc/qubes-vm.directory.template $RPM_BUILD_ROOT/usr/share/qubes/
|
||||
cp misc/qubes-templatevm.directory.template $RPM_BUILD_ROOT/usr/share/qubes/
|
||||
cp misc/qubes-appmenu-select.desktop $RPM_BUILD_ROOT/usr/share/qubes/
|
||||
cp misc/vm-template.conf $RPM_BUILD_ROOT/usr/share/qubes/
|
||||
cp misc/vm-template-hvm.conf $RPM_BUILD_ROOT/usr/share/qubes/
|
||||
|
||||
mkdir -p $RPM_BUILD_ROOT/usr/bin
|
||||
cp ../network/qubes_setup_dnat_to_ns $RPM_BUILD_ROOT/usr/lib/qubes
|
||||
@ -344,6 +345,7 @@ fi
|
||||
/usr/share/qubes/qubes-templatevm.directory.template
|
||||
/usr/share/qubes/qubes-appmenu-select.desktop
|
||||
/usr/share/qubes/vm-template.conf
|
||||
/usr/share/qubes/vm-template-hvm.conf
|
||||
/usr/lib/qubes/qubes_setup_dnat_to_ns
|
||||
/usr/lib/qubes/qubes_fix_nm_conf.sh
|
||||
/etc/dhclient.d/qubes_setup_dnat_to_ns.sh
|
||||
|
36
vchan/Makefile.stubdom
Normal file
36
vchan/Makefile.stubdom
Normal file
@ -0,0 +1,36 @@
|
||||
#
|
||||
# The Qubes OS Project, http://www.qubes-os.org
|
||||
#
|
||||
# Copyright (C) 2012 Marek Marczykowski <marmarek@invisiblethingslab.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
#
|
||||
|
||||
# Assume it is placed as xen-root/tools/vchan
|
||||
|
||||
XEN_ROOT = ../..
|
||||
include $(XEN_ROOT)/tools/Rules.mk
|
||||
|
||||
CFLAGS+=-Wall -I$(XEN_ROOT)/tools/libxc -DCONFIG_STUBDOM
|
||||
all: libvchan.a
|
||||
|
||||
libvchan.a: init.o io.o
|
||||
$(AR) rc $@ $^
|
||||
|
||||
clean:
|
||||
rm -f *.o *so *~ client server node node-select
|
||||
|
||||
|
93
vchan/init.c
93
vchan/init.c
@ -19,6 +19,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
@ -29,25 +32,38 @@
|
||||
#include <xenctrl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <mm.h>
|
||||
#include "libvchan.h"
|
||||
#ifndef CONFIG_STUBDOM
|
||||
#include "../u2mfn/u2mfnlib.h"
|
||||
#endif
|
||||
|
||||
static int ring_init(struct libvchan *ctrl)
|
||||
{
|
||||
int u2mfn = open("/proc/u2mfn", O_RDONLY);
|
||||
int mfn;
|
||||
struct vchan_interface *ring;
|
||||
#ifdef CONFIG_STUBDOM
|
||||
ring = (struct vchan_interface *) memalign(XC_PAGE_SIZE, sizeof(*ring));
|
||||
|
||||
if (!ring)
|
||||
return -1;
|
||||
|
||||
|
||||
mfn = virtual_to_mfn(ring);
|
||||
#else
|
||||
int u2mfn = open("/proc/u2mfn", O_RDONLY);
|
||||
ring = (struct vchan_interface *) u2mfn_alloc_kpage ();
|
||||
|
||||
|
||||
if (ring == MAP_FAILED)
|
||||
return -1;
|
||||
|
||||
ctrl->ring = ring;
|
||||
if (u2mfn_get_last_mfn (&mfn) < 0)
|
||||
return -1;
|
||||
|
||||
ctrl->ring_ref = mfn;
|
||||
close(u2mfn);
|
||||
#endif
|
||||
|
||||
ctrl->ring = ring;
|
||||
ctrl->ring_ref = mfn;
|
||||
ring->cons_in = ring->prod_in = ring->cons_out = ring->prod_out =
|
||||
0;
|
||||
ring->server_closed = ring->client_closed = 0;
|
||||
@ -65,13 +81,18 @@ static int server_interface_init(struct libvchan *ctrl, int devno)
|
||||
struct xs_handle *xs;
|
||||
char buf[64];
|
||||
char ref[16];
|
||||
/* XXX temp hack begin */
|
||||
char *domid_s;
|
||||
int domid = 0;
|
||||
unsigned int len;
|
||||
/* XXX temp hack end */
|
||||
#ifdef XENCTRL_HAS_XC_INTERFACE
|
||||
xc_evtchn *evfd;
|
||||
#else
|
||||
int evfd;
|
||||
#endif
|
||||
evtchn_port_or_error_t port;
|
||||
xs = xs_domain_open();
|
||||
xs = xs_daemon_open();
|
||||
if (!xs) {
|
||||
return ret;
|
||||
}
|
||||
@ -90,20 +111,41 @@ static int server_interface_init(struct libvchan *ctrl, int devno)
|
||||
if (port < 0)
|
||||
goto fail2;
|
||||
ctrl->evport = port;
|
||||
ctrl->devno = devno;
|
||||
|
||||
// stubdom debug HACK XXX
|
||||
domid_s = xs_read(xs, 0, "domid", &len);
|
||||
if (domid_s)
|
||||
domid = atoi(domid_s);
|
||||
|
||||
snprintf(ref, sizeof ref, "%d", ctrl->ring_ref);
|
||||
snprintf(buf, sizeof buf, "device/vchan/%d/ring-ref", devno);
|
||||
if (!xs_write(xs, 0, buf, ref, strlen(ref)))
|
||||
#ifdef CONFIG_STUBDOM
|
||||
// TEMP HACK XXX FIXME goto fail2;
|
||||
fprintf(stderr, "xenstore-write /local/domain/%d/%s %s\n", domid, buf, ref);
|
||||
#else
|
||||
goto fail2;
|
||||
#endif
|
||||
snprintf(ref, sizeof ref, "%d", ctrl->evport);
|
||||
snprintf(buf, sizeof buf, "device/vchan/%d/event-channel", devno);
|
||||
if (!xs_write(xs, 0, buf, ref, strlen(ref)))
|
||||
#ifdef CONFIG_STUBDOM
|
||||
// TEMP HACK XXX FIXME goto fail2;
|
||||
fprintf(stderr, "xenstore-write /local/domain/%d/%s %s\n", domid, buf, ref);
|
||||
#else
|
||||
goto fail2;
|
||||
#endif
|
||||
// do not block in stubdom - libvchan_server_handle_connected will be
|
||||
// called on first input
|
||||
#ifndef CONFIG_STUBDOM
|
||||
// wait for the peer to arrive
|
||||
if (xc_evtchn_pending(evfd) == -1)
|
||||
goto fail2;
|
||||
xc_evtchn_unmask(ctrl->evfd, ctrl->evport);
|
||||
snprintf(buf, sizeof buf, "device/vchan/%d", devno);
|
||||
xs_rm(xs, 0, buf);
|
||||
#endif
|
||||
|
||||
ret = 0;
|
||||
fail2:
|
||||
@ -129,8 +171,8 @@ static int server_interface_init(struct libvchan *ctrl, int devno)
|
||||
ctrl->rd_ring_size = sizeof(ctrl->ring->buf_##dir2)
|
||||
|
||||
/**
|
||||
Run in AppVM (any domain).
|
||||
Sleeps until the connection is established.
|
||||
Run in AppVM (any domain).
|
||||
Sleeps until the connection is established. (unless in stubdom)
|
||||
\param devno something like a well-known port.
|
||||
\returns NULL on failure, handle on success
|
||||
*/
|
||||
@ -156,6 +198,39 @@ struct libvchan *libvchan_server_init(int devno)
|
||||
return ctrl;
|
||||
}
|
||||
|
||||
int libvchan_server_handle_connected(struct libvchan *ctrl)
|
||||
{
|
||||
struct xs_handle *xs;
|
||||
char buf[64];
|
||||
int ret = -1;
|
||||
int libvchan_fd;
|
||||
fd_set rfds;
|
||||
|
||||
xs = xs_daemon_open();
|
||||
if (!xs) {
|
||||
return ret;
|
||||
}
|
||||
// clear the pending flag
|
||||
xc_evtchn_pending(ctrl->evfd);
|
||||
|
||||
snprintf(buf, sizeof buf, "device/vchan/%d", ctrl->devno);
|
||||
xs_rm(xs, 0, buf);
|
||||
|
||||
ret = 0;
|
||||
|
||||
#if 0
|
||||
fail2:
|
||||
if (ret)
|
||||
#ifdef XENCTRL_HAS_XC_INTERFACE
|
||||
xc_evtchn_close(ctrl->evfd);
|
||||
#else
|
||||
close(ctrl->evfd);
|
||||
#endif
|
||||
#endif
|
||||
xs_daemon_close(xs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
retrieves ring-ref and event-channel numbers from xenstore (if
|
||||
they don't exist, return error, because nobody seems to listen);
|
||||
@ -250,7 +325,7 @@ static int client_interface_init(struct libvchan *ctrl, int domain, int devno)
|
||||
/**
|
||||
Run on the client side of connection (currently, must be dom0).
|
||||
\returns NULL on failure (e.g. noone listening), handle on success
|
||||
*/
|
||||
*/
|
||||
struct libvchan *libvchan_client_init(int domain, int devno)
|
||||
{
|
||||
struct libvchan *ctrl =
|
||||
|
19
vchan/io.c
19
vchan/io.c
@ -22,6 +22,8 @@
|
||||
#include "libvchan.h"
|
||||
#include <xenctrl.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/select.h>
|
||||
/**
|
||||
\return How much data is immediately available for reading
|
||||
*/
|
||||
@ -67,7 +69,24 @@ int libvchan_is_eof(struct libvchan *ctrl)
|
||||
int libvchan_wait(struct libvchan *ctrl)
|
||||
{
|
||||
int ret;
|
||||
#ifndef CONFIG_STUBDOM
|
||||
ret = xc_evtchn_pending(ctrl->evfd);
|
||||
#else
|
||||
int vchan_fd = libvchan_fd_for_select(ctrl);
|
||||
fd_set rfds;
|
||||
|
||||
libvchan_prepare_to_select(ctrl);
|
||||
while ((ret = xc_evtchn_pending(ctrl->evfd)) < 0) {
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(0, &rfds);
|
||||
FD_SET(vchan_fd, &rfds);
|
||||
ret = select(vchan_fd + 1, &rfds, NULL, NULL, NULL);
|
||||
if (ret < 0 && errno != EINTR) {
|
||||
perror("select");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (ret!=-1 && xc_evtchn_unmask(ctrl->evfd, ctrl->evport))
|
||||
return -1;
|
||||
if (ret!=-1 && libvchan_is_eof(ctrl))
|
||||
|
@ -19,6 +19,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _LIBVCHAN_H
|
||||
#define _LIBVCHAN_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <xenctrl.h>
|
||||
typedef uint32_t VCHAN_RING_IDX;
|
||||
@ -44,6 +47,7 @@ struct libvchan {
|
||||
int evfd;
|
||||
#endif
|
||||
int evport;
|
||||
int devno;
|
||||
VCHAN_RING_IDX *wr_cons, *wr_prod, *rd_cons, *rd_prod;
|
||||
char *rd_ring, *wr_ring;
|
||||
int rd_ring_size, wr_ring_size;
|
||||
@ -51,6 +55,7 @@ struct libvchan {
|
||||
};
|
||||
|
||||
struct libvchan *libvchan_server_init(int devno);
|
||||
int libvchan_server_handle_connected(struct libvchan *ctrl);
|
||||
|
||||
struct libvchan *libvchan_client_init(int domain, int devno);
|
||||
|
||||
@ -63,3 +68,5 @@ int libvchan_fd_for_select(struct libvchan *ctrl);
|
||||
int libvchan_is_eof(struct libvchan *ctrl);
|
||||
int libvchan_data_ready(struct libvchan *ctrl);
|
||||
int libvchan_buffer_space(struct libvchan *ctrl);
|
||||
|
||||
#endif /* _LIBVCHAN_H */
|
||||
|
Loading…
Reference in New Issue
Block a user