diff --git a/tools/examples/xmexample.hvm b/tools/examples/xmexample.hvm index 33ce3203d3..06662a0d17 100644 --- a/tools/examples/xmexample.hvm +++ b/tools/examples/xmexample.hvm @@ -179,6 +179,10 @@ serial='pty' #localtime=1 +#----------------------------------------------------------------------------- +# set the real time clock offset in seconds [default=0 i.e. same as dom0] +#rtc_timeoffset=3600 + #----------------------------------------------------------------------------- # start in full screen #full-screen=1 diff --git a/tools/ioemu/target-i386-dm/helper2.c b/tools/ioemu/target-i386-dm/helper2.c index 17261e632d..8b98e8a184 100644 --- a/tools/ioemu/target-i386-dm/helper2.c +++ b/tools/ioemu/target-i386-dm/helper2.c @@ -74,6 +74,8 @@ int vcpus = 1; int xc_handle; +long time_offset = 0; + shared_iopage_t *shared_page = NULL; #define BUFFER_IO_MAX_DELAY 100 @@ -439,6 +441,34 @@ void cpu_ioreq_xor(CPUState *env, ioreq_t *req) req->data = tmp1; } +void timeoffset_get() +{ + char *p; + + p = xenstore_vm_read(domid, "rtc/timeoffset", NULL); + if (!p) + return; + + if (sscanf(p, "%ld", &time_offset) == 1) + fprintf(logfile, "Time offset set %ld\n", time_offset); + else + time_offset = 0; + + xc_domain_set_time_offset(xc_handle, domid, time_offset); + + free(p); +} + +void cpu_ioreq_timeoffset(CPUState *env, ioreq_t *req) +{ + char b[64]; + + time_offset += (ulong)req->data; + + sprintf(b, "%ld", time_offset); + xenstore_vm_write(domid, "rtc/timeoffset", b); +} + void cpu_ioreq_xchg(CPUState *env, ioreq_t *req) { unsigned long tmp1; @@ -478,6 +508,9 @@ void __handle_ioreq(CPUState *env, ioreq_t *req) case IOREQ_TYPE_XCHG: cpu_ioreq_xchg(env, req); break; + case IOREQ_TYPE_TIMEOFFSET: + cpu_ioreq_timeoffset(env, req); + break; default: hw_error("Invalid ioreq type 0x%x\n", req->type); } diff --git a/tools/ioemu/vl.c b/tools/ioemu/vl.c index 66174de66f..4ec5e0817d 100644 --- a/tools/ioemu/vl.c +++ b/tools/ioemu/vl.c @@ -6670,6 +6670,9 @@ int main(int argc, char **argv) } free(page_array); #endif + + timeoffset_get(); + #else /* !CONFIG_DM */ phys_ram_base = qemu_vmalloc(phys_ram_size); diff --git a/tools/ioemu/vl.h b/tools/ioemu/vl.h index a6b53aa312..4ef250f766 100644 --- a/tools/ioemu/vl.h +++ b/tools/ioemu/vl.h @@ -1276,6 +1276,12 @@ int xenstore_unsubscribe_from_hotplug_status(struct xs_handle *handle, const char *inst, const char *token); +int xenstore_vm_write(int domid, char *key, char *val); +char *xenstore_vm_read(int domid, char *key, int *len); + +/* helper2.c */ +extern long time_offset; +void timeoffset_get(void); /* xen_platform.c */ void pci_xen_platform_init(PCIBus *bus); diff --git a/tools/ioemu/xenstore.c b/tools/ioemu/xenstore.c index 26063f5a93..77819cea67 100644 --- a/tools/ioemu/xenstore.c +++ b/tools/ioemu/xenstore.c @@ -567,3 +567,72 @@ int xenstore_unsubscribe_from_hotplug_status(struct xs_handle *handle, return rc; } + +char *xenstore_vm_read(int domid, char *key, int *len) +{ + char *buf = NULL, *path = NULL, *value = NULL; + + if (xsh == NULL) + goto out; + + path = xs_get_domain_path(xsh, domid); + if (path == NULL) { + fprintf(logfile, "xs_get_domain_path(%d): error\n", domid); + goto out; + } + + pasprintf(&buf, "%s/vm", path); + free(path); + path = xs_read(xsh, XBT_NULL, buf, NULL); + if (path == NULL) { + fprintf(logfile, "xs_read(%s): read error\n", buf); + goto out; + } + + pasprintf(&buf, "%s/%s", path, key); + value = xs_read(xsh, XBT_NULL, buf, len); + if (value == NULL) { + fprintf(logfile, "xs_read(%s): read error\n", buf); + goto out; + } + + out: + free(path); + free(buf); + return value; +} + +int xenstore_vm_write(int domid, char *key, char *value) +{ + char *buf = NULL, *path = NULL; + int rc = -1; + + if (xsh == NULL) + goto out; + + path = xs_get_domain_path(xsh, domid); + if (path == NULL) { + fprintf(logfile, "xs_get_domain_path(%d): error\n"); + goto out; + } + + pasprintf(&buf, "%s/vm", path); + free(path); + path = xs_read(xsh, XBT_NULL, buf, NULL); + if (path == NULL) { + fprintf(logfile, "xs_read(%s): read error\n", buf); + goto out; + } + + pasprintf(&buf, "%s/%s", path, key); + rc = xs_write(xsh, XBT_NULL, buf, value, strlen(value)); + if (rc) { + fprintf(logfile, "xs_write(%s, %s): write error\n", buf, key); + goto out; + } + + out: + free(path); + free(buf); + return rc; +} diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index e36e89a0df..a4a9d43fe5 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -118,7 +118,7 @@ LEGACY_CFG_TO_XENAPI_CFG = reverse_dict(XENAPI_CFG_TO_LEGACY_CFG) # Platform configuration keys. XENAPI_PLATFORM_CFG = [ 'acpi', 'apic', 'boot', 'device_model', 'display', 'fda', 'fdb', 'keymap', 'isa', 'localtime', - 'nographic', 'pae', 'serial', 'sdl', + 'nographic', 'pae', 'rtc_timeoffset', 'serial', 'sdl', 'soundhw','stdvga', 'usb', 'usbdevice', 'vnc', 'vncconsole', 'vncdisplay', 'vnclisten', 'vncpasswd', 'vncunused', 'xauthority'] @@ -203,6 +203,7 @@ LEGACY_CFG_TYPES = { 'on_xend_stop': str, 'on_xend_start': str, 'online_vcpus': int, + 'rtc/timeoffset': str, } # Values that should be stored in xenstore's /vm/ that is used diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 7ba20fb566..425776ce12 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -859,7 +859,8 @@ class XendDomainInfo: # Check whether values in the configuration have # changed in Xenstore. - cfg_vm = ['name', 'on_poweroff', 'on_reboot', 'on_crash'] + cfg_vm = ['name', 'on_poweroff', 'on_reboot', 'on_crash', + 'rtc/timeoffset'] vm_details = self._readVMDetails([(k,XendConfig.LEGACY_CFG_TYPES[k]) for k in cfg_vm]) @@ -888,6 +889,11 @@ class XendDomainInfo: self.info.update_with_image_sxp(sxp.from_string(image_sxp)) changed = True + # Check if the rtc offset has changes + if vm_details.get("rtc/timeoffset", 0) != self.info["platform"].get("rtc_timeoffset", 0): + self.info["platform"]["rtc_timeoffset"] = vm_details.get("rtc/timeoffset", 0) + changed = True + if changed: # Update the domain section of the store, as this contains some # parameters derived from the VM configuration. diff --git a/tools/python/xen/xend/image.py b/tools/python/xen/xend/image.py index d9e850ccc9..835a5d8060 100644 --- a/tools/python/xen/xend/image.py +++ b/tools/python/xen/xend/image.py @@ -256,9 +256,12 @@ class HVMImageHandler(ImageHandler): self.xauthority = vmConfig['platform'].get('xauthority') self.vncconsole = vmConfig['platform'].get('vncconsole') + rtc_timeoffset = vmConfig['platform'].get('rtc_timeoffset') + self.vm.storeVm(("image/dmargs", " ".join(self.dmargs)), ("image/device-model", self.device_model), ("image/display", self.display)) + self.vm.storeVm(("rtc/timeoffset", rtc_timeoffset)) self.pid = None diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py index 0ae94d83c4..1411f9be89 100644 --- a/tools/python/xen/xm/create.py +++ b/tools/python/xen/xm/create.py @@ -186,6 +186,10 @@ gopts.var('cpus', val='CPUS', fn=set_value, default=None, use="CPUS to run the domain on.") +gopts.var('rtc_timeoffset', val='RTC_TIMEOFFSET', + fn=set_value, default="0", + use="Set RTC offset.") + gopts.var('pae', val='PAE', fn=set_int, default=1, use="Disable or enable PAE of HVM domain.") @@ -717,7 +721,7 @@ def configure_hvm(config_image, vals): args = [ 'device_model', 'pae', 'vcpus', 'boot', 'fda', 'fdb', 'localtime', 'serial', 'stdvga', 'isa', 'nographic', 'soundhw', 'vnc', 'vncdisplay', 'vncunused', 'vncconsole', 'vnclisten', - 'sdl', 'display', 'xauthority', + 'sdl', 'display', 'xauthority', 'rtc_timeoffset', 'acpi', 'apic', 'usb', 'usbdevice', 'keymap' ] for a in args: if a in vals.__dict__ and vals.__dict__[a] is not None: diff --git a/xen/arch/x86/hvm/intercept.c b/xen/arch/x86/hvm/intercept.c index 3de58812c3..fb8497a996 100644 --- a/xen/arch/x86/hvm/intercept.c +++ b/xen/arch/x86/hvm/intercept.c @@ -155,28 +155,13 @@ static inline void hvm_mmio_access(struct vcpu *v, } } -int hvm_buffered_io_intercept(ioreq_t *p) +int hvm_buffered_io_send(ioreq_t *p) { struct vcpu *v = current; spinlock_t *buffered_io_lock; buffered_iopage_t *buffered_iopage = (buffered_iopage_t *)(v->domain->arch.hvm_domain.buffered_io_va); unsigned long tmp_write_pointer = 0; - int i; - - /* ignore READ ioreq_t! */ - if ( p->dir == IOREQ_READ ) - return 0; - - for ( i = 0; i < HVM_BUFFERED_IO_RANGE_NR; i++ ) { - if ( p->addr >= hvm_buffered_io_ranges[i]->start_addr && - p->addr + p->size - 1 < hvm_buffered_io_ranges[i]->start_addr + - hvm_buffered_io_ranges[i]->length ) - break; - } - - if ( i == HVM_BUFFERED_IO_RANGE_NR ) - return 0; buffered_io_lock = &v->domain->arch.hvm_domain.buffered_io_lock; spin_lock(buffered_io_lock); @@ -205,6 +190,27 @@ int hvm_buffered_io_intercept(ioreq_t *p) return 1; } +int hvm_buffered_io_intercept(ioreq_t *p) +{ + int i; + + /* ignore READ ioreq_t! */ + if ( p->dir == IOREQ_READ ) + return 0; + + for ( i = 0; i < HVM_BUFFERED_IO_RANGE_NR; i++ ) { + if ( p->addr >= hvm_buffered_io_ranges[i]->start_addr && + p->addr + p->size - 1 < hvm_buffered_io_ranges[i]->start_addr + + hvm_buffered_io_ranges[i]->length ) + break; + } + + if ( i == HVM_BUFFERED_IO_RANGE_NR ) + return 0; + + return hvm_buffered_io_send(p); +} + int hvm_mmio_intercept(ioreq_t *p) { struct vcpu *v = current; diff --git a/xen/arch/x86/hvm/platform.c b/xen/arch/x86/hvm/platform.c index 185a7c2f55..d8a751bd1d 100644 --- a/xen/arch/x86/hvm/platform.c +++ b/xen/arch/x86/hvm/platform.c @@ -921,6 +921,26 @@ static void send_mmio_req(unsigned char type, unsigned long gpa, hvm_send_assist_req(v); } +void send_timeoffset_req(unsigned long timeoff) +{ + ioreq_t p[1]; + + if ( timeoff == 0 ) + return; + + memset(p, 0, sizeof(*p)); + + p->type = IOREQ_TYPE_TIMEOFFSET; + p->size = 4; + p->dir = IOREQ_WRITE; + p->data = timeoff; + + p->state = STATE_IOREQ_READY; + + if ( !hvm_buffered_io_send(p) ) + printk("Unsuccessful timeoffset update\n"); +} + static void mmio_operands(int type, unsigned long gpa, struct hvm_io_op *mmio_op, unsigned char op_size) diff --git a/xen/arch/x86/hvm/rtc.c b/xen/arch/x86/hvm/rtc.c index 036eba7bfe..1b18dca204 100644 --- a/xen/arch/x86/hvm/rtc.c +++ b/xen/arch/x86/hvm/rtc.c @@ -157,6 +157,10 @@ static inline int from_bcd(RTCState *s, int a) static void rtc_set_time(RTCState *s) { struct tm *tm = &s->current_tm; + unsigned long before, after; /* XXX s_time_t */ + + before = mktime(tm->tm_year, tm->tm_mon, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); tm->tm_sec = from_bcd(s, s->hw.cmos_data[RTC_SECONDS]); tm->tm_min = from_bcd(s, s->hw.cmos_data[RTC_MINUTES]); @@ -168,6 +172,10 @@ static void rtc_set_time(RTCState *s) tm->tm_mday = from_bcd(s, s->hw.cmos_data[RTC_DAY_OF_MONTH]); tm->tm_mon = from_bcd(s, s->hw.cmos_data[RTC_MONTH]) - 1; tm->tm_year = from_bcd(s, s->hw.cmos_data[RTC_YEAR]) + 100; + + after = mktime(tm->tm_year, tm->tm_mon, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + send_timeoffset_req(after - before); } static void rtc_copy_date(RTCState *s) diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c index daba20ff39..d31fa17984 100644 --- a/xen/arch/x86/time.c +++ b/xen/arch/x86/time.c @@ -573,7 +573,7 @@ static void init_platform_timer(void) * machines were long is 32-bit! (However, as time_t is signed, we * will already get problems at other places on 2038-01-19 03:14:08) */ -static inline unsigned long +unsigned long mktime (unsigned int year, unsigned int mon, unsigned int day, unsigned int hour, unsigned int min, unsigned int sec) diff --git a/xen/include/asm-x86/hvm/io.h b/xen/include/asm-x86/hvm/io.h index 092b037516..cf46b0cb6d 100644 --- a/xen/include/asm-x86/hvm/io.h +++ b/xen/include/asm-x86/hvm/io.h @@ -127,6 +127,7 @@ static inline int hvm_portio_intercept(ioreq_t *p) } extern int hvm_mmio_intercept(ioreq_t *p); +extern int hvm_buffered_io_send(ioreq_t *p); extern int hvm_buffered_io_intercept(ioreq_t *p); static inline int register_portio_handler( @@ -145,6 +146,7 @@ static inline int irq_masked(unsigned long eflags) extern void send_pio_req(unsigned long port, unsigned long count, int size, paddr_t value, int dir, int df, int value_is_ptr); +void send_timeoffset_req(unsigned long timeoff); extern void handle_mmio(unsigned long gpa); extern void hvm_interrupt_post(struct vcpu *v, int vector, int type); extern void hvm_io_assist(struct vcpu *v); diff --git a/xen/include/asm-x86/time.h b/xen/include/asm-x86/time.h index 731ce9500e..df74cf2962 100644 --- a/xen/include/asm-x86/time.h +++ b/xen/include/asm-x86/time.h @@ -16,4 +16,9 @@ static inline cycles_t get_cycles(void) return c; } +unsigned long +mktime (unsigned int year, unsigned int mon, + unsigned int day, unsigned int hour, + unsigned int min, unsigned int sec); + #endif /* __X86_TIME_H__ */ diff --git a/xen/include/public/hvm/ioreq.h b/xen/include/public/hvm/ioreq.h index 4ff8936a5a..646246e854 100644 --- a/xen/include/public/hvm/ioreq.h +++ b/xen/include/public/hvm/ioreq.h @@ -39,6 +39,7 @@ #define IOREQ_TYPE_XOR 4 #define IOREQ_TYPE_XCHG 5 #define IOREQ_TYPE_ADD 6 +#define IOREQ_TYPE_TIMEOFFSET 7 /* * VMExit dispatcher should cooperate with instruction decoder to