diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c index 4f1d8561da..51117117f4 100644 --- a/tools/libxc/xc_domain.c +++ b/tools/libxc/xc_domain.c @@ -286,6 +286,17 @@ int xc_domain_setmaxmem(int xc_handle, return do_dom0_op(xc_handle, &op); } +int xc_domain_set_time_offset(int xc_handle, + uint32_t domid, + int32_t time_offset_seconds) +{ + DECLARE_DOM0_OP; + op.cmd = DOM0_SETTIMEOFFSET; + op.u.settimeoffset.domain = (domid_t)domid; + op.u.settimeoffset.time_offset_seconds = time_offset_seconds; + return do_dom0_op(xc_handle, &op); +} + int xc_domain_memory_increase_reservation(int xc_handle, uint32_t domid, unsigned long nr_extents, diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h index f6093752b6..c18f1807ab 100644 --- a/tools/libxc/xenctrl.h +++ b/tools/libxc/xenctrl.h @@ -410,6 +410,10 @@ int xc_domain_setmaxmem(int xc_handle, uint32_t domid, unsigned int max_memkb); +int xc_domain_set_time_offset(int xc_handle, + uint32_t domid, + int32_t time_offset_seconds); + int xc_domain_memory_increase_reservation(int xc_handle, uint32_t domid, unsigned long nr_extents, diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c index d85f0f7107..db42ab058a 100644 --- a/tools/python/xen/lowlevel/xc/xc.c +++ b/tools/python/xen/lowlevel/xc/xc.c @@ -869,6 +869,30 @@ static PyObject *pyxc_domain_iomem_permission(PyObject *self, return zero; } +static PyObject *pyxc_domain_set_time_offset(XcObject *self, PyObject *args) +{ + uint32_t dom; + int32_t time_offset_seconds; + time_t calendar_time; + struct tm local_time; + struct tm utc_time; + + if (!PyArg_ParseTuple(args, "i", &dom)) + return NULL; + + calendar_time = time(NULL); + localtime_r(&calendar_time, &local_time); + gmtime_r(&calendar_time, &utc_time); + /* set up to get calendar time based on utc_time, with local dst setting */ + utc_time.tm_isdst = local_time.tm_isdst; + time_offset_seconds = (int32_t)difftime(calendar_time, mktime(&utc_time)); + + if (xc_domain_set_time_offset(self->xc_handle, dom, time_offset_seconds) != 0) + return NULL; + + Py_INCREF(zero); + return zero; +} static PyObject *dom_op(XcObject *self, PyObject *args, int (*fn)(int, uint32_t)) @@ -1208,6 +1232,13 @@ static PyMethodDef pyxc_methods[] = { "Returns: [int]: The size in KiB of memory spanning the given number " "of pages.\n" }, + { "domain_set_time_offset", + (PyCFunction)pyxc_domain_set_time_offset, + METH_VARARGS, "\n" + "Set a domain's time offset to Dom0's localtime\n" + " dom [int]: Domain whose time offset is being set.\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + { NULL, NULL, 0, NULL } }; diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 0dd3a54eef..665eb927d3 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -135,6 +135,7 @@ ROUNDTRIPPING_CONFIG_ENTRIES = [ ('bootloader', str), ('bootloader_args', str), ('features', str), + ('localtime', int), ] ROUNDTRIPPING_CONFIG_ENTRIES += VM_CONFIG_PARAMS @@ -1260,6 +1261,10 @@ class XendDomainInfo: self.info['image'], self.info['device']) + localtime = self.info['localtime'] + if localtime is not None and localtime == 1: + xc.domain_set_time_offset(self.domid) + xc.domain_setcpuweight(self.domid, self.info['cpu_weight']) # repin domain vcpus if a restricted cpus list is provided diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py index f4e05ae667..3eadebb37d 100644 --- a/tools/python/xen/xm/create.py +++ b/tools/python/xen/xm/create.py @@ -672,6 +672,8 @@ def make_config(vals): config.append(['backend', ['netif']]) if vals.tpmif: config.append(['backend', ['tpmif']]) + if vals.localtime: + config.append(['localtime', vals.localtime]) config_image = configure_image(vals) if vals.bootloader: diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c index 54a3ce41d4..9d344b8349 100644 --- a/xen/arch/x86/time.c +++ b/xen/arch/x86/time.c @@ -699,7 +699,7 @@ void update_domain_wallclock_time(struct domain *d) { spin_lock(&wc_lock); version_update_begin(&d->shared_info->wc_version); - d->shared_info->wc_sec = wc_sec; + d->shared_info->wc_sec = wc_sec + d->time_offset_seconds; d->shared_info->wc_nsec = wc_nsec; version_update_end(&d->shared_info->wc_version); spin_unlock(&wc_lock); diff --git a/xen/common/dom0_ops.c b/xen/common/dom0_ops.c index a6e437abd1..91cbc60be8 100644 --- a/xen/common/dom0_ops.c +++ b/xen/common/dom0_ops.c @@ -693,6 +693,21 @@ long do_dom0_op(XEN_GUEST_HANDLE(dom0_op_t) u_dom0_op) break; #endif + case DOM0_SETTIMEOFFSET: + { + struct domain *d; + + ret = -ESRCH; + d = find_domain_by_id(op->u.settimeoffset.domain); + if ( d != NULL ) + { + d->time_offset_seconds = op->u.settimeoffset.time_offset_seconds; + put_domain(d); + ret = 0; + } + } + break; + default: ret = arch_do_dom0_op(op, u_dom0_op); break; diff --git a/xen/include/public/dom0_ops.h b/xen/include/public/dom0_ops.h index 07affaa699..d1113b655b 100644 --- a/xen/include/public/dom0_ops.h +++ b/xen/include/public/dom0_ops.h @@ -527,6 +527,14 @@ typedef struct dom0_domain_setup { } dom0_domain_setup_t; DEFINE_XEN_GUEST_HANDLE(dom0_domain_setup_t); +#define DOM0_SETTIMEOFFSET 50 +struct dom0_settimeoffset { + domid_t domain; + int32_t time_offset_seconds; /* applied to domain wallclock time */ +}; +typedef struct dom0_settimeoffset dom0_settimeoffset_t; +DEFINE_XEN_GUEST_HANDLE(dom0_settimeoffset_t); + struct dom0_op { uint32_t cmd; uint32_t interface_version; /* DOM0_INTERFACE_VERSION */ @@ -569,6 +577,7 @@ struct dom0_op { struct dom0_iomem_permission iomem_permission; struct dom0_hypercall_init hypercall_init; struct dom0_domain_setup domain_setup; + struct dom0_settimeoffset settimeoffset; uint8_t pad[128]; } u; }; diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index 70869a51af..e78ff4f619 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -159,6 +159,7 @@ struct domain /* OProfile support. */ struct xenoprof *xenoprof; + int32_t time_offset_seconds; }; struct domain_setup_info