Daniel P. Berrange
2007-Aug-22 22:26 UTC
[Xen-devel] PATCH: 0/10: Merge paravirt FB & console into qemu-dm
The following series of 10 patches is a merge of the xenfb and xenconsoled functionality into the qemu-dm code. The general approach taken is to have qemu-dm provide two machine types - one for xen paravirt, the other for fullyvirt. For compatability the later is the default. The goals overall are to kill LibVNCServer, remove alot of code duplication and/or parallel impls of the same concepts, and increase the functionality for PV. In particular this will let paravirt guests take advantage of TLS encryption for the VNC server, and let us configure the text console in all the variety of ways QEMU supports (PTY, File, TCP, TCP_Telnet,UDP, etc). One interesting possiblity that merging the text & graphics consoles into same daemon allows for, is to expose the pygrub screens over both a PTY and VNC server at the same time. If I can figure out how to actually code this idea it would solve a major headache when using bootloaders with PV guests remotely. The patches should be applied in order - after each individual patch you should still have a fully operational system for both FV & PV. I have tested save/restore, save+checkpoint, and migration for fullyvirt, paravirt with SUSPEND_CANCEL, and paravirt without SUSPEND_CANCEL. With the latter I get sporadic failures - both with and without my changes - so I think that''s a more general compat problem in xen-unstable.hg. I''ve included diffstats inline with each patch, but since there''s a fair bit of general re-factoring / moving code in intermediate patches here is a summary of the stats for the series as a whole. I recommend applying each patch individually though to preserve the history of changes. Config.mk | 1 a/tools/check/check_libvncserver | 38 - a/tools/check/check_sdl | 27 a/tools/xenfb/Makefile | 32 a/tools/xenfb/sdlfb.c | 342 ---------- a/tools/xenfb/vncfb.c | 522 --------------- a/tools/xenfb/xenfb.c | 785 ----------------------- a/tools/xenfb/xenfb.h | 35 - b/tools/ioemu/hw/xen_console.c | 424 ++++++++++++ b/tools/ioemu/hw/xen_console.h | 25 b/tools/ioemu/hw/xen_machine_fv.c | 286 ++++++++ b/tools/ioemu/hw/xen_machine_pv.c | 74 ++ b/tools/ioemu/hw/xenfb.c | 1051 ++++++++++++++++++++++++++++++++ b/tools/ioemu/hw/xenfb.h | 13 tools/Makefile | 1 tools/check/Makefile | 4 tools/console/daemon/io.c | 9 tools/ioemu/Makefile.target | 4 tools/ioemu/target-i386-dm/helper2.c | 5 tools/ioemu/vl.c | 249 ------- tools/ioemu/vl.h | 4 tools/ioemu/xenstore.c | 2 tools/python/xen/xend/XendCheckpoint.py | 5 tools/python/xen/xend/XendConfig.py | 35 - tools/python/xen/xend/XendDomainInfo.py | 41 - tools/python/xen/xend/image.py | 379 ++++++----- tools/python/xen/xend/server/vfbif.py | 110 --- 27 files changed, 2165 insertions(+), 2338 deletions(-) Signed-off-by: Daniel P. Berrange <berrange@redhat.com> Dan. -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=| _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel P. Berrange
2007-Aug-22 22:28 UTC
Re: [Xen-devel] PATCH: 1/10: Add a QEMU machine type for fullvirt guests
This patch does a (no functional change) re-arrangement of the code for starting up a fully virtualized guest. In particular it creates a new QEMU machine type for Xen fullyvirt guests which can be specified with ''-M xenfv''. For compatability this is in fact made to be the default. The code for setting up memory maps is moved out of vl.c, and into hw/xen_machine_fv.c. This is basically to ensure that it can be easily skipped when we add a paravirt machine type in the next patch. b/tools/ioemu/hw/xen_machine_fv.c | 286 ++++++++++++++++++++++++++++++++++++++ tools/ioemu/Makefile.target | 1 tools/ioemu/vl.c | 244 -------------------------------- tools/ioemu/vl.h | 3 4 files changed, 295 insertions(+), 239 deletions(-) Signed-off-by: Daniel P. Berrange <berrange@redhat.com> Dan. diff -r 7953164cebb6 tools/ioemu/Makefile.target --- a/tools/ioemu/Makefile.target Tue Aug 07 09:07:29 2007 +0100 +++ b/tools/ioemu/Makefile.target Wed Aug 15 14:14:55 2007 -0400 @@ -400,6 +400,7 @@ VL_OBJS+= piix4acpi.o VL_OBJS+= piix4acpi.o VL_OBJS+= xenstore.o VL_OBJS+= xen_platform.o +VL_OBJS+= xen_machine_fv.o VL_OBJS+= tpm_tis.o CPPFLAGS += -DHAS_AUDIO endif diff -r 7953164cebb6 tools/ioemu/hw/xen_machine_fv.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/ioemu/hw/xen_machine_fv.c Wed Aug 15 14:15:25 2007 -0400 @@ -0,0 +1,286 @@ +/* + * QEMU Xen FV Machine + * + * Copyright (c) 2003-2007 Fabrice Bellard + * Copyright (c) 2007 Red Hat + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "vl.h" +#include <xen/hvm/params.h> +#include <sys/mman.h> + +#if defined(MAPCACHE) + +#if defined(__i386__) +#define MAX_MCACHE_SIZE 0x40000000 /* 1GB max for x86 */ +#define MCACHE_BUCKET_SHIFT 16 +#elif defined(__x86_64__) +#define MAX_MCACHE_SIZE 0x1000000000 /* 64GB max for x86_64 */ +#define MCACHE_BUCKET_SHIFT 20 +#endif + +#define MCACHE_BUCKET_SIZE (1UL << MCACHE_BUCKET_SHIFT) + +#define BITS_PER_LONG (sizeof(long)*8) +#define BITS_TO_LONGS(bits) \ + (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG) +#define DECLARE_BITMAP(name,bits) \ + unsigned long name[BITS_TO_LONGS(bits)] +#define test_bit(bit,map) \ + (!!((map)[(bit)/BITS_PER_LONG] & (1UL << ((bit)%BITS_PER_LONG)))) + +struct map_cache { + unsigned long paddr_index; + uint8_t *vaddr_base; + DECLARE_BITMAP(valid_mapping, MCACHE_BUCKET_SIZE>>PAGE_SHIFT); +}; + +static struct map_cache *mapcache_entry; +static unsigned long nr_buckets; + +/* For most cases (>99.9%), the page address is the same. */ +static unsigned long last_address_index = ~0UL; +static uint8_t *last_address_vaddr; + +static int qemu_map_cache_init(void) +{ + unsigned long size; + + nr_buckets = (((MAX_MCACHE_SIZE >> PAGE_SHIFT) + + (1UL << (MCACHE_BUCKET_SHIFT - PAGE_SHIFT)) - 1) >> + (MCACHE_BUCKET_SHIFT - PAGE_SHIFT)); + fprintf(logfile, "qemu_map_cache_init nr_buckets = %lx\n", nr_buckets); + + /* + * Use mmap() directly: lets us allocate a big hash table with no up-front + * cost in storage space. The OS will allocate memory only for the buckets + * that we actually use. All others will contain all zeroes. + */ + size = nr_buckets * sizeof(struct map_cache); + size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); + mapcache_entry = mmap(NULL, size, PROT_READ|PROT_WRITE, + MAP_SHARED|MAP_ANONYMOUS, 0, 0); + if (mapcache_entry == MAP_FAILED) { + errno = ENOMEM; + return -1; + } + + return 0; +} + +static void qemu_remap_bucket(struct map_cache *entry, + unsigned long address_index) +{ + uint8_t *vaddr_base; + unsigned long pfns[MCACHE_BUCKET_SIZE >> PAGE_SHIFT]; + unsigned int i, j; + + if (entry->vaddr_base != NULL) { + errno = munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE); + if (errno) { + fprintf(logfile, "unmap fails %d\n", errno); + exit(-1); + } + } + + for (i = 0; i < MCACHE_BUCKET_SIZE >> PAGE_SHIFT; i++) + pfns[i] = (address_index << (MCACHE_BUCKET_SHIFT-PAGE_SHIFT)) + i; + + vaddr_base = xc_map_foreign_batch(xc_handle, domid, PROT_READ|PROT_WRITE, + pfns, MCACHE_BUCKET_SIZE >> PAGE_SHIFT); + if (vaddr_base == NULL) { + fprintf(logfile, "xc_map_foreign_batch error %d\n", errno); + exit(-1); + } + + entry->vaddr_base = vaddr_base; + entry->paddr_index = address_index; + + for (i = 0; i < MCACHE_BUCKET_SIZE >> PAGE_SHIFT; i += BITS_PER_LONG) { + unsigned long word = 0; + j = ((i + BITS_PER_LONG) > (MCACHE_BUCKET_SIZE >> PAGE_SHIFT)) ? + (MCACHE_BUCKET_SIZE >> PAGE_SHIFT) % BITS_PER_LONG : BITS_PER_LONG; + while (j > 0) + word = (word << 1) | !(pfns[i + --j] & 0xF0000000UL); + entry->valid_mapping[i / BITS_PER_LONG] = word; + } +} + +uint8_t *qemu_map_cache(target_phys_addr_t phys_addr) +{ + struct map_cache *entry; + unsigned long address_index = phys_addr >> MCACHE_BUCKET_SHIFT; + unsigned long address_offset = phys_addr & (MCACHE_BUCKET_SIZE-1); + + if (address_index == last_address_index) + return last_address_vaddr + address_offset; + + entry = &mapcache_entry[address_index % nr_buckets]; + + if (entry->vaddr_base == NULL || entry->paddr_index != address_index || + !test_bit(address_offset>>PAGE_SHIFT, entry->valid_mapping)) + qemu_remap_bucket(entry, address_index); + + if (!test_bit(address_offset>>PAGE_SHIFT, entry->valid_mapping)) + return NULL; + + last_address_index = address_index; + last_address_vaddr = entry->vaddr_base; + + return last_address_vaddr + address_offset; +} + +void qemu_invalidate_map_cache(void) +{ + unsigned long i; + + mapcache_lock(); + + for (i = 0; i < nr_buckets; i++) { + struct map_cache *entry = &mapcache_entry[i]; + + if (entry->vaddr_base == NULL) + continue; + + errno = munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE); + if (errno) { + fprintf(logfile, "unmap fails %d\n", errno); + exit(-1); + } + + entry->paddr_index = 0; + entry->vaddr_base = NULL; + } + + last_address_index = ~0UL; + last_address_vaddr = NULL; + + mapcache_unlock(); +} + +#endif /* defined(MAPCACHE) */ + + +static void xen_init_fv(uint64_t ram_size, int vga_ram_size, char *boot_device, + DisplayState *ds, const char **fd_filename, + int snapshot, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename) +{ + unsigned long ioreq_pfn; + extern void *shared_page; + extern void *buffered_io_page; +#ifdef __ia64__ + unsigned long nr_pages; + xen_pfn_t *page_array; + extern void *buffered_pio_page; +#endif + +#if defined(__i386__) || defined(__x86_64__) + + if (qemu_map_cache_init()) { + fprintf(logfile, "qemu_map_cache_init returned: error %d\n", errno); + exit(-1); + } + + xc_get_hvm_param(xc_handle, domid, HVM_PARAM_IOREQ_PFN, &ioreq_pfn); + fprintf(logfile, "shared page at pfn %lx\n", ioreq_pfn); + shared_page = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, + PROT_READ|PROT_WRITE, ioreq_pfn); + if (shared_page == NULL) { + fprintf(logfile, "map shared IO page returned error %d\n", errno); + exit(-1); + } + + xc_get_hvm_param(xc_handle, domid, HVM_PARAM_BUFIOREQ_PFN, &ioreq_pfn); + fprintf(logfile, "buffered io page at pfn %lx\n", ioreq_pfn); + buffered_io_page = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, + PROT_READ|PROT_WRITE, ioreq_pfn); + if (buffered_io_page == NULL) { + fprintf(logfile, "map buffered IO page returned error %d\n", errno); + exit(-1); + } + +#elif defined(__ia64__) + + nr_pages = ram_size/PAGE_SIZE; + + page_array = (xen_pfn_t *)malloc(nr_pages * sizeof(xen_pfn_t)); + if (page_array == NULL) { + fprintf(logfile, "malloc returned error %d\n", errno); + exit(-1); + } + + shared_page = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, + PROT_READ|PROT_WRITE, + IO_PAGE_START >> PAGE_SHIFT); + + buffered_io_page =xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, + PROT_READ|PROT_WRITE, + BUFFER_IO_PAGE_START >> PAGE_SHIFT); + + buffered_pio_page = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, + PROT_READ|PROT_WRITE, + BUFFER_PIO_PAGE_START >> PAGE_SHIFT); + + for (i = 0; i < nr_pages; i++) + page_array[i] = i; + + /* VTI will not use memory between 3G~4G, so we just pass a legal pfn + to make QEMU map continuous virtual memory space */ + if (ram_size > MMIO_START) { + for (i = 0 ; i < (MEM_G >> PAGE_SHIFT); i++) + page_array[(MMIO_START >> PAGE_SHIFT) + i] + (STORE_PAGE_START >> PAGE_SHIFT); + } + + phys_ram_base = xc_map_foreign_batch(xc_handle, domid, + PROT_READ|PROT_WRITE, + page_array, nr_pages); + if (phys_ram_base == 0) { + fprintf(logfile, "xc_map_foreign_batch returned error %d\n", errno); + exit(-1); + } + free(page_array); +#endif + + timeoffset_get(); + + + pc_machine.init(ram_size, vga_ram_size, boot_device, ds, fd_filename, + snapshot, kernel_filename, kernel_cmdline, initrd_filename); +} + +QEMUMachine xenfv_machine = { + "xenfv", + "Xen Fully-virtualized PC", + xen_init_fv, +}; + +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -r 7953164cebb6 tools/ioemu/vl.c --- a/tools/ioemu/vl.c Tue Aug 07 09:07:29 2007 +0100 +++ b/tools/ioemu/vl.c Wed Aug 15 14:16:53 2007 -0400 @@ -89,7 +89,6 @@ #include "exec-all.h" -#include <xen/hvm/params.h> #define DEFAULT_NETWORK_SCRIPT "/etc/xen/qemu-ifup" #define DEFAULT_BRIDGE "xenbr0" #ifdef __sun__ @@ -6647,8 +6646,12 @@ void register_machines(void) void register_machines(void) { #if defined(TARGET_I386) +#ifndef CONFIG_DM qemu_register_machine(&pc_machine); qemu_register_machine(&isapc_machine); +#else + qemu_register_machine(&xenfv_machine); +#endif #elif defined(TARGET_PPC) qemu_register_machine(&heathrow_machine); qemu_register_machine(&core99_machine); @@ -6856,156 +6859,6 @@ int set_mm_mapping(int xc_handle, uint32 return 0; } -#if defined(MAPCACHE) - -#if defined(__i386__) -#define MAX_MCACHE_SIZE 0x40000000 /* 1GB max for x86 */ -#define MCACHE_BUCKET_SHIFT 16 -#elif defined(__x86_64__) -#define MAX_MCACHE_SIZE 0x1000000000 /* 64GB max for x86_64 */ -#define MCACHE_BUCKET_SHIFT 20 -#endif - -#define MCACHE_BUCKET_SIZE (1UL << MCACHE_BUCKET_SHIFT) - -#define BITS_PER_LONG (sizeof(long)*8) -#define BITS_TO_LONGS(bits) \ - (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG) -#define DECLARE_BITMAP(name,bits) \ - unsigned long name[BITS_TO_LONGS(bits)] -#define test_bit(bit,map) \ - (!!((map)[(bit)/BITS_PER_LONG] & (1UL << ((bit)%BITS_PER_LONG)))) - -struct map_cache { - unsigned long paddr_index; - uint8_t *vaddr_base; - DECLARE_BITMAP(valid_mapping, MCACHE_BUCKET_SIZE>>PAGE_SHIFT); -}; - -static struct map_cache *mapcache_entry; -static unsigned long nr_buckets; - -/* For most cases (>99.9%), the page address is the same. */ -static unsigned long last_address_index = ~0UL; -static uint8_t *last_address_vaddr; - -static int qemu_map_cache_init(void) -{ - unsigned long size; - - nr_buckets = (((MAX_MCACHE_SIZE >> PAGE_SHIFT) + - (1UL << (MCACHE_BUCKET_SHIFT - PAGE_SHIFT)) - 1) >> - (MCACHE_BUCKET_SHIFT - PAGE_SHIFT)); - fprintf(logfile, "qemu_map_cache_init nr_buckets = %lx\n", nr_buckets); - - /* - * Use mmap() directly: lets us allocate a big hash table with no up-front - * cost in storage space. The OS will allocate memory only for the buckets - * that we actually use. All others will contain all zeroes. - */ - size = nr_buckets * sizeof(struct map_cache); - size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); - mapcache_entry = mmap(NULL, size, PROT_READ|PROT_WRITE, - MAP_SHARED|MAP_ANONYMOUS, 0, 0); - if (mapcache_entry == MAP_FAILED) { - errno = ENOMEM; - return -1; - } - - return 0; -} - -static void qemu_remap_bucket(struct map_cache *entry, - unsigned long address_index) -{ - uint8_t *vaddr_base; - unsigned long pfns[MCACHE_BUCKET_SIZE >> PAGE_SHIFT]; - unsigned int i, j; - - if (entry->vaddr_base != NULL) { - errno = munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE); - if (errno) { - fprintf(logfile, "unmap fails %d\n", errno); - exit(-1); - } - } - - for (i = 0; i < MCACHE_BUCKET_SIZE >> PAGE_SHIFT; i++) - pfns[i] = (address_index << (MCACHE_BUCKET_SHIFT-PAGE_SHIFT)) + i; - - vaddr_base = xc_map_foreign_batch(xc_handle, domid, PROT_READ|PROT_WRITE, - pfns, MCACHE_BUCKET_SIZE >> PAGE_SHIFT); - if (vaddr_base == NULL) { - fprintf(logfile, "xc_map_foreign_batch error %d\n", errno); - exit(-1); - } - - entry->vaddr_base = vaddr_base; - entry->paddr_index = address_index; - - for (i = 0; i < MCACHE_BUCKET_SIZE >> PAGE_SHIFT; i += BITS_PER_LONG) { - unsigned long word = 0; - j = ((i + BITS_PER_LONG) > (MCACHE_BUCKET_SIZE >> PAGE_SHIFT)) ? - (MCACHE_BUCKET_SIZE >> PAGE_SHIFT) % BITS_PER_LONG : BITS_PER_LONG; - while (j > 0) - word = (word << 1) | !(pfns[i + --j] & 0xF0000000UL); - entry->valid_mapping[i / BITS_PER_LONG] = word; - } -} - -uint8_t *qemu_map_cache(target_phys_addr_t phys_addr) -{ - struct map_cache *entry; - unsigned long address_index = phys_addr >> MCACHE_BUCKET_SHIFT; - unsigned long address_offset = phys_addr & (MCACHE_BUCKET_SIZE-1); - - if (address_index == last_address_index) - return last_address_vaddr + address_offset; - - entry = &mapcache_entry[address_index % nr_buckets]; - - if (entry->vaddr_base == NULL || entry->paddr_index != address_index || - !test_bit(address_offset>>PAGE_SHIFT, entry->valid_mapping)) - qemu_remap_bucket(entry, address_index); - - if (!test_bit(address_offset>>PAGE_SHIFT, entry->valid_mapping)) - return NULL; - - last_address_index = address_index; - last_address_vaddr = entry->vaddr_base; - - return last_address_vaddr + address_offset; -} - -void qemu_invalidate_map_cache(void) -{ - unsigned long i; - - mapcache_lock(); - - for (i = 0; i < nr_buckets; i++) { - struct map_cache *entry = &mapcache_entry[i]; - - if (entry->vaddr_base == NULL) - continue; - - errno = munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE); - if (errno) { - fprintf(logfile, "unmap fails %d\n", errno); - exit(-1); - } - - entry->paddr_index = 0; - entry->vaddr_base = NULL; - } - - last_address_index = ~0UL; - last_address_vaddr = NULL; - - mapcache_unlock(); -} - -#endif /* defined(MAPCACHE) */ int main(int argc, char **argv) { @@ -7040,14 +6893,6 @@ int main(int argc, char **argv) char usb_devices[MAX_USB_CMDLINE][128]; int usb_devices_index; int fds[2]; - unsigned long ioreq_pfn; - extern void *shared_page; - extern void *buffered_io_page; -#ifdef __ia64__ - unsigned long nr_pages; - xen_pfn_t *page_array; - extern void *buffered_pio_page; -#endif sigset_t set; char qemu_dm_logfilename[128]; @@ -7602,6 +7447,7 @@ int main(int argc, char **argv) #ifdef CONFIG_DM bdrv_init(); + xc_handle = xc_interface_open(); xenstore_parse_domain_config(domid); #endif /* CONFIG_DM */ @@ -7695,83 +7541,6 @@ int main(int argc, char **argv) } phys_ram_size += ret; } -#endif /* !CONFIG_DM */ - -#ifdef CONFIG_DM - - xc_handle = xc_interface_open(); - -#if defined(__i386__) || defined(__x86_64__) - - if (qemu_map_cache_init()) { - fprintf(logfile, "qemu_map_cache_init returned: error %d\n", errno); - exit(-1); - } - - xc_get_hvm_param(xc_handle, domid, HVM_PARAM_IOREQ_PFN, &ioreq_pfn); - fprintf(logfile, "shared page at pfn %lx\n", ioreq_pfn); - shared_page = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, - PROT_READ|PROT_WRITE, ioreq_pfn); - if (shared_page == NULL) { - fprintf(logfile, "map shared IO page returned error %d\n", errno); - exit(-1); - } - - xc_get_hvm_param(xc_handle, domid, HVM_PARAM_BUFIOREQ_PFN, &ioreq_pfn); - fprintf(logfile, "buffered io page at pfn %lx\n", ioreq_pfn); - buffered_io_page = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, - PROT_READ|PROT_WRITE, ioreq_pfn); - if (buffered_io_page == NULL) { - fprintf(logfile, "map buffered IO page returned error %d\n", errno); - exit(-1); - } - -#elif defined(__ia64__) - - nr_pages = ram_size/PAGE_SIZE; - - page_array = (xen_pfn_t *)malloc(nr_pages * sizeof(xen_pfn_t)); - if (page_array == NULL) { - fprintf(logfile, "malloc returned error %d\n", errno); - exit(-1); - } - - shared_page = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, - PROT_READ|PROT_WRITE, - IO_PAGE_START >> PAGE_SHIFT); - - buffered_io_page =xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, - PROT_READ|PROT_WRITE, - BUFFER_IO_PAGE_START >> PAGE_SHIFT); - - buffered_pio_page = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, - PROT_READ|PROT_WRITE, - BUFFER_PIO_PAGE_START >> PAGE_SHIFT); - - for (i = 0; i < nr_pages; i++) - page_array[i] = i; - - /* VTI will not use memory between 3G~4G, so we just pass a legal pfn - to make QEMU map continuous virtual memory space */ - if (ram_size > MMIO_START) { - for (i = 0 ; i < (MEM_G >> PAGE_SHIFT); i++) - page_array[(MMIO_START >> PAGE_SHIFT) + i] - (STORE_PAGE_START >> PAGE_SHIFT); - } - - phys_ram_base = xc_map_foreign_batch(xc_handle, domid, - PROT_READ|PROT_WRITE, - page_array, nr_pages); - if (phys_ram_base == 0) { - fprintf(logfile, "xc_map_foreign_batch returned error %d\n", errno); - exit(-1); - } - free(page_array); -#endif - - timeoffset_get(); - -#else /* !CONFIG_DM */ phys_ram_base = qemu_vmalloc(phys_ram_size); if (!phys_ram_base) { @@ -7779,9 +7548,6 @@ int main(int argc, char **argv) exit(1); } -#endif /* !CONFIG_DM */ - -#ifndef CONFIG_DM /* we always create the cdrom drive, even if no disk is there */ bdrv_init(); if (cdrom_index >= 0) { diff -r 7953164cebb6 tools/ioemu/vl.h --- a/tools/ioemu/vl.h Tue Aug 07 09:07:29 2007 +0100 +++ b/tools/ioemu/vl.h Wed Aug 15 14:14:55 2007 -0400 @@ -1118,6 +1118,9 @@ extern void pci_piix4_acpi_init(PCIBus * /* pc.c */ extern QEMUMachine pc_machine; extern QEMUMachine isapc_machine; +#ifdef CONFIG_DM +extern QEMUMachine xenfv_machine; +#endif extern int fd_bootchk; void ioport_set_a20(int enable); -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=| _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel P. Berrange
2007-Aug-22 22:29 UTC
Re: [Xen-devel] PATCH: 2/10: Add a QEMU machine type for paravirt guests
This patch adds a paravirt machine type to QEMU. THis can be requested by passing the arg ''-M xenpv'' to qemu-dm. Aside from -d, and -domain-name, the only other args that are processed are the VNC / SDL graphics related args. Any others will be ignored. A tweak to helper2.c was made to stop it setting up a file handler watch when there are no CPUs registered. The paravirt machine is in hw/xen_machine_pv.c and registers an instance of the xenfb class, integrating it with the QEMU event loop and key/mouse handlers. A couple of methods were adding to xenfb.h to allow direct access to the file handles for xenstore & the event channel. The vfbif.py device controller is modified to launch qemu-dm instead of the old xen-vncfb / sdlfb daemons. When receiving framebuffer updates from the guest, the update has to be copied into QEMU''s copy of the framebuffer. This is because QEMU stores the framebuffer in the format that is native to the SDL display, or VNC client. This is not neccessarily the same as the guest framebuffer which is always 32bpp. If there is an exact depth match we use memcpy for speed, but in the non-matching case we have to fallback to slow code to covert pixel formats. It fully supports all features of the paravirt framebuffer including the choice between absolute & relative pointers. To avoid both moving the xenfb.c and making changes to it in the same patch, this just uses a Makefile hack to link against the xenfb.o from the tools/xenfb/ directory. This will be removed in the following patch. b/tools/ioemu/hw/xen_machine_pv.c | 231 ++++++++++++++++++++++++++++++++++ tools/ioemu/Makefile.target | 2 tools/ioemu/target-i386-dm/helper2.c | 5 tools/ioemu/vl.c | 5 tools/ioemu/vl.h | 1 tools/python/xen/xend/server/vfbif.py | 26 +-- tools/xenfb/xenfb.c | 80 ++++++++--- tools/xenfb/xenfb.h | 4 8 files changed, 317 insertions(+), 37 deletions(-) Signed-off-by: Daniel P. Berrange <berrange@redhat.com> Dan. diff -r 327024163186 tools/ioemu/Makefile.target --- a/tools/ioemu/Makefile.target Tue Aug 14 12:52:54 2007 -0400 +++ b/tools/ioemu/Makefile.target Tue Aug 14 13:26:18 2007 -0400 @@ -401,6 +401,8 @@ VL_OBJS+= xenstore.o VL_OBJS+= xenstore.o VL_OBJS+= xen_platform.o VL_OBJS+= xen_machine_fv.o +VL_OBJS+= xen_machine_pv.o +VL_OBJS+= ../../xenfb/xenfb.o VL_OBJS+= tpm_tis.o CPPFLAGS += -DHAS_AUDIO endif diff -r 327024163186 tools/ioemu/hw/xen_machine_pv.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/ioemu/hw/xen_machine_pv.c Tue Aug 14 14:21:29 2007 -0400 @@ -0,0 +1,231 @@ +/* + * QEMU Xen PV Machine + * + * Copyright (c) 2007 Red Hat + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "vl.h" +#include "../../xenfb/xenfb.h" +#include <linux/input.h> + +/* A convenient function for munging pixels between different depths */ +#define BLT(SRC_T,DST_T,RLS,GLS,BLS,RRS,GRS,BRS,RM,GM,BM) \ + for (line = y ; line < h ; line++) { \ + SRC_T *src = (SRC_T *)(xenfb->pixels + (line*xenfb->row_stride) + (x*xenfb->depth/8)); \ + DST_T *dst = (DST_T *)(ds->data + (line*ds->linesize) + (x*ds->depth/8)); \ + int col; \ + for (col = x ; col < w ; col++) { \ + *dst = (((*src >> RRS)&RM) << RLS) | \ + (((*src >> GRS)&GM) << GLS) | \ + (((*src >> GRS)&BM) << BLS); \ + src++; \ + dst++; \ + } \ + } + + +/* This copies data from the guest framebuffer region, into QEMU''s copy + * NB. QEMU''s copy is stored in the pixel format of a) the local X server (SDL case) + * or b) the current VNC client pixel format. + */ +static void xen_pvfb_guest_copy(struct xenfb *xenfb, int x, int y, int w, int h) +{ + DisplayState *ds = (DisplayState *)xenfb->user_data; + int line; + + if (xenfb->depth == ds->depth) { /* Perfect match can use fast path */ + for (line = y ; line < (y+h) ; line++) { + memcpy(ds->data + (line * ds->linesize) + (x*ds->depth/8), + xenfb->pixels + (line*xenfb->row_stride) + (x*xenfb->depth/8), + w * xenfb->depth/8); + } + } else { /* Mismatch requires slow pixel munging */ + if (xenfb->depth == 8) { + /* 8 bit source == r:3 g:3 b:2 */ + if (ds->depth == 16) { + BLT(uint8_t, uint16_t, 5, 2, 0, 11, 5, 0, 7, 7, 3); + } else if (ds->depth == 32) { + BLT(uint8_t, uint32_t, 5, 2, 0, 16, 8, 0, 7, 7, 3); + } + } else if (xenfb->depth == 16) { + /* 16 bit source == r:5 g:6 b:5 */ + if (ds->depth == 8) { + BLT(uint16_t, uint8_t, 11, 5, 0, 5, 2, 0, 31, 63, 31); + } else if (ds->depth == 32) { + BLT(uint16_t, uint32_t, 11, 5, 0, 16, 8, 0, 31, 63, 31); + } + } else if (xenfb->depth == 32) { + /* 32 bit source == r:8 g:8 b:8 (padding:8) */ + if (ds->depth == 8) { + BLT(uint32_t, uint8_t, 16, 8, 0, 5, 2, 0, 255, 255, 255); + } else if (ds->depth == 16) { + BLT(uint32_t, uint16_t, 16, 8, 0, 11, 5, 0, 255, 255, 255); + } + } + } + dpy_update(ds, x, y, w, h); +} + + +/* Send a keypress from the client to the guest OS */ +static void xen_pvfb_put_keycode(void *opaque, int keycode) +{ + struct xenfb *xenfb = (struct xenfb*)opaque; + xenfb_send_key(xenfb, keycode & 0x80 ? 0 : 1, keycode & 0x7f); +} + +/* Send a mouse event from the client to the guest OS */ +static void xen_pvfb_mouse_event(void *opaque, + int dx, int dy, int dz, int button_state) +{ + static int old_state = 0; + int i; + struct xenfb *xenfb = (struct xenfb*)opaque; + DisplayState *ds = (DisplayState *)xenfb->user_data; + if (xenfb->abs_pointer_wanted) + xenfb_send_position(xenfb, + dx*ds->width/0x7fff, + dy*ds->height/0x7fff); + else + xenfb_send_motion(xenfb, dx, dy); + + for (i = 0 ; i < 8 ; i++) { + int lastDown = old_state & (1 << i); + int down = button_state & (1 << i); + if (down == lastDown) + continue; + + if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0) + return; + } + old_state = button_state; +} + +/* QEMU display state changed, so refresh the framebuffer copy */ +void xen_pvfb_update(void *opaque) +{ + struct xenfb *xenfb = (struct xenfb *)opaque; + xen_pvfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height); +} + +/* QEMU display state changed, so refresh the framebuffer copy */ +void xen_pvfb_invalidate(void *opaque) +{ + struct xenfb *xenfb = (struct xenfb *)opaque; + xen_pvfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height); +} + +/* Screen dump is not used in Xen, so no need to impl this ? */ +void xen_pvfb_screen_dump(void *opaque, const char *name) { } + +void xen_pvfb_dispatch_store(void *opaque) { + int ret; + if ((ret = xenfb_dispatch_store((struct xenfb *)opaque)) < 0) { + fprintf(stderr, "Failure while dispatching store: %d\n", ret); + exit(1); + } +} + +void xen_pvfb_dispatch_channel(void *opaque) { + int ret; + if ((ret = xenfb_dispatch_channel((struct xenfb *)opaque)) < 0) { + fprintf(stderr, "Failure while dispatching store: %d\n", ret); + exit(1); + } +} + +/* The Xen PV machine currently provides + * - a virtual framebuffer + * - .... + */ +static void xen_init_pv(uint64_t ram_size, int vga_ram_size, char *boot_device, + DisplayState *ds, const char **fd_filename, + int snapshot, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename) +{ + struct xenfb *xenfb; + extern int domid; + int fd; + + /* Prepare PVFB state */ + xenfb = xenfb_new(); + if (xenfb == NULL) { + fprintf(stderr, "Could not create framebuffer (%s)\n", + strerror(errno)); + exit(1); + } + + /* Talk to the guest */ + if (xenfb_attach_dom(xenfb, domid) < 0) { + fprintf(stderr, "Could not connect to domain (%s)\n", + strerror(errno)); + exit(1); + } + xenfb->update = xen_pvfb_guest_copy; + xenfb->user_data = ds; + + /* Tell QEMU to allocate a graphical console */ + graphic_console_init(ds, + xen_pvfb_update, + xen_pvfb_invalidate, + xen_pvfb_screen_dump, + xenfb); + + /* Register our keyboard & mouse handlers */ + qemu_add_kbd_event_handler(xen_pvfb_put_keycode, xenfb); + qemu_add_mouse_event_handler(xen_pvfb_mouse_event, xenfb, + xenfb->abs_pointer_wanted, + "Xen PVFB Mouse"); + + /* Listen for events from xenstore */ + fd = xenfb_get_store_fd(xenfb); + if (qemu_set_fd_handler2(fd, NULL, xen_pvfb_dispatch_store, NULL, xenfb) < 0) { + fprintf(stderr, "Could not register event handler (%s)\n", + strerror(errno)); + } + + /* Listen for events from the event channel */ + fd = xenfb_get_channel_fd(xenfb); + if (qemu_set_fd_handler2(fd, NULL, xen_pvfb_dispatch_channel, NULL, xenfb) < 0) { + fprintf(stderr, "Could not register event handler (%s)\n", + strerror(errno)); + } + + /* Setup QEMU display */ + dpy_resize(ds, xenfb->width, xenfb->height); +} + +QEMUMachine xenpv_machine = { + "xenpv", + "Xen Para-virtualized PC", + xen_init_pv, +}; + +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -r 327024163186 tools/ioemu/target-i386-dm/helper2.c --- a/tools/ioemu/target-i386-dm/helper2.c Tue Aug 14 12:52:54 2007 -0400 +++ b/tools/ioemu/target-i386-dm/helper2.c Tue Aug 14 12:58:46 2007 -0400 @@ -616,7 +616,7 @@ int main_loop(void) extern int shutdown_requested; extern int suspend_requested; CPUState *env = cpu_single_env; - int evtchn_fd = xc_evtchn_fd(xce_handle); + int evtchn_fd = xce_handle == -1 ? -1 : xc_evtchn_fd(xce_handle); char qemu_file[PATH_MAX]; fd_set fds; @@ -624,7 +624,8 @@ int main_loop(void) cpu_single_env); qemu_mod_timer(buffered_io_timer, qemu_get_clock(rt_clock)); - qemu_set_fd_handler(evtchn_fd, cpu_handle_ioreq, NULL, env); + if (evtchn_fd != -1) + qemu_set_fd_handler(evtchn_fd, cpu_handle_ioreq, NULL, env); xenstore_record_dm_state("running"); while (1) { diff -r 327024163186 tools/ioemu/vl.c --- a/tools/ioemu/vl.c Tue Aug 14 12:52:54 2007 -0400 +++ b/tools/ioemu/vl.c Tue Aug 14 13:50:44 2007 -0400 @@ -182,7 +182,7 @@ extern int vcpus; int xc_handle; -char domain_name[64] = "Xen-HVM-no-name"; +char domain_name[64] = "Xen-no-name"; extern int domid; char vncpasswd[64]; @@ -6651,6 +6651,7 @@ void register_machines(void) qemu_register_machine(&isapc_machine); #else qemu_register_machine(&xenfv_machine); + qemu_register_machine(&xenpv_machine); #endif #elif defined(TARGET_PPC) qemu_register_machine(&heathrow_machine); @@ -7370,7 +7371,7 @@ int main(int argc, char **argv) break; case QEMU_OPTION_domainname: snprintf(domain_name, sizeof(domain_name), - "Xen-HVM-%s", optarg); + "Xen-%s", optarg); break; case QEMU_OPTION_d: domid = atoi(optarg); diff -r 327024163186 tools/ioemu/vl.h --- a/tools/ioemu/vl.h Tue Aug 14 12:52:54 2007 -0400 +++ b/tools/ioemu/vl.h Tue Aug 14 12:55:35 2007 -0400 @@ -1120,6 +1120,7 @@ extern QEMUMachine isapc_machine; extern QEMUMachine isapc_machine; #ifdef CONFIG_DM extern QEMUMachine xenfv_machine; +extern QEMUMachine xenpv_machine; #endif extern int fd_bootchk; diff -r 327024163186 tools/python/xen/xend/server/vfbif.py --- a/tools/python/xen/xend/server/vfbif.py Tue Aug 14 12:52:54 2007 -0400 +++ b/tools/python/xen/xend/server/vfbif.py Tue Aug 14 14:15:52 2007 -0400 @@ -50,8 +50,10 @@ class VfbifController(DevController): # is HVM, so qemu-dm will handle the vfb. return - std_args = [ "--domid", "%d" % self.vm.getDomid(), - "--title", self.vm.getName() ] + args = [ xen.util.auxbin.pathTo("qemu-dm"), + "-M", "xenpv", + "-d", "%d" % self.vm.getDomid(), + "-domain-name", self.vm.getName() ] t = config.get("type", None) if t == "vnc": passwd = None @@ -65,15 +67,14 @@ class VfbifController(DevController): else: log.debug("No VNC passwd configured for vfb access") - # Try to start the vnc backend - args = [xen.util.auxbin.pathTo("xen-vncfb")] - if config.has_key("vncunused"): - args += ["--unused"] - elif config.has_key("vncdisplay"): - args += ["--vncport", "%d" % (5900 + int(config["vncdisplay"]))] - vnclisten = config.get("vnclisten", + vnclisten = config.get(''vnclisten'', xen.xend.XendOptions.instance().get_vnclisten_address()) - args += [ "--listen", vnclisten ] + vncdisplay = config.get(''vncdisplay'', 0) + args += [''-vnc'', "%s:%d" % (vnclisten, vncdisplay)] + + if config.get(''vncunused'', 0): + args += [''-vncunused''] + if config.has_key("keymap"): args += ["-k", "%s" % config["keymap"]] else: @@ -81,15 +82,14 @@ class VfbifController(DevController): if xoptions.get_keymap(): args += ["-k", "%s" % xoptions.get_keymap()] - spawn_detached(args[0], args + std_args, os.environ) + spawn_detached(args[0], args, os.environ) elif t == "sdl": - args = [xen.util.auxbin.pathTo("xen-sdlfb")] env = dict(os.environ) if config.has_key("display"): env[''DISPLAY''] = config["display"] if config.has_key("xauthority"): env[''XAUTHORITY''] = config["xauthority"] - spawn_detached(args[0], args + std_args, env) + spawn_detached(args[0], args, env) else: raise VmError(''Unknown vfb type %s (%s)'' % (t, repr(config))) diff -r 327024163186 tools/xenfb/xenfb.c --- a/tools/xenfb/xenfb.c Tue Aug 14 12:52:54 2007 -0400 +++ b/tools/xenfb/xenfb.c Tue Aug 14 13:41:54 2007 -0400 @@ -676,37 +676,58 @@ static int xenfb_on_state_change(struct return 0; } -/* Returns 0 normally, -1 on error, or -2 if the domain went away. */ -int xenfb_poll(struct xenfb *xenfb_pub, fd_set *readfds) +int xenfb_dispatch_channel(struct xenfb *xenfb_pub) { struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; evtchn_port_t port; + port = xc_evtchn_pending(xenfb->evt_xch); + if (port == -1) + return -1; + + if (port == xenfb->fb.port) + xenfb_on_fb_event(xenfb); + else if (port == xenfb->kbd.port) + xenfb_on_kbd_event(xenfb); + + if (xc_evtchn_unmask(xenfb->evt_xch, port) == -1) + return -1; + + return 0; +} + +int xenfb_dispatch_store(struct xenfb *xenfb_pub) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; unsigned dummy; char **vec; int r; + vec = xs_read_watch(xenfb->xsh, &dummy); + free(vec); + r = xenfb_on_state_change(&xenfb->fb); + if (r == 0) + r = xenfb_on_state_change(&xenfb->kbd); + if (r == -1) + return -2; + + return 0; +} + + +/* Returns 0 normally, -1 on error, or -2 if the domain went away. */ +int xenfb_poll(struct xenfb *xenfb_pub, fd_set *readfds) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + int ret; + if (FD_ISSET(xc_evtchn_fd(xenfb->evt_xch), readfds)) { - port = xc_evtchn_pending(xenfb->evt_xch); - if (port == -1) - return -1; - - if (port == xenfb->fb.port) - xenfb_on_fb_event(xenfb); - else if (port == xenfb->kbd.port) - xenfb_on_kbd_event(xenfb); - - if (xc_evtchn_unmask(xenfb->evt_xch, port) == -1) - return -1; + if ((ret = xenfb_dispatch_channel(xenfb_pub)) < 0) + return ret; } if (FD_ISSET(xs_fileno(xenfb->xsh), readfds)) { - vec = xs_read_watch(xenfb->xsh, &dummy); - free(vec); - r = xenfb_on_state_change(&xenfb->fb); - if (r == 0) - r = xenfb_on_state_change(&xenfb->kbd); - if (r == -1) - return -2; + if ((ret = xenfb_dispatch_store(xenfb_pub)) < 0) + return ret; } return 0; @@ -721,6 +742,18 @@ int xenfb_select_fds(struct xenfb *xenfb FD_SET(fd1, readfds); FD_SET(fd2, readfds); return fd1 > fd2 ? fd1 + 1 : fd2 + 1; +} + +int xenfb_get_store_fd(struct xenfb *xenfb_pub) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + return xs_fileno(xenfb->xsh); +} + +int xenfb_get_channel_fd(struct xenfb *xenfb_pub) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + return xc_evtchn_fd(xenfb->evt_xch); } static int xenfb_kbd_event(struct xenfb_private *xenfb, @@ -783,3 +816,10 @@ int xenfb_send_position(struct xenfb *xe return xenfb_kbd_event(xenfb, &event); } +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff -r 327024163186 tools/xenfb/xenfb.h --- a/tools/xenfb/xenfb.h Tue Aug 14 12:52:54 2007 -0400 +++ b/tools/xenfb/xenfb.h Tue Aug 14 13:42:04 2007 -0400 @@ -25,8 +25,12 @@ void xenfb_teardown(struct xenfb *xenfb) int xenfb_attach_dom(struct xenfb *xenfb, int domid); +int xenfb_dispatch_store(struct xenfb *xenfb_pub); +int xenfb_dispatch_channel(struct xenfb *xenfb_pub); int xenfb_select_fds(struct xenfb *xenfb, fd_set *readfds); int xenfb_poll(struct xenfb *xenfb, fd_set *readfds); +int xenfb_get_store_fd(struct xenfb *xenfb_pub); +int xenfb_get_channel_fd(struct xenfb *xenfb_pub); int xenfb_send_key(struct xenfb *xenfb, bool down, int keycode); int xenfb_send_motion(struct xenfb *xenfb, int rel_x, int rel_y); -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=| _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel P. Berrange
2007-Aug-22 22:29 UTC
Re: [Xen-devel] PATCH: 3/10: Remove standalone xenfb code
This patch removes all trace of the standalone paravirt framebuffer daemon. With this there is no longer any requirement for LibVNCServer. Everything is handled by the QEMU device model. The xenfb.c and xenfb.h files are now moved (without code change) into tools/ioemu/hw/ & the temporary Makefile hack from the previous patch is removed. Config.mk | 1 a/tools/check/check_libvncserver | 38 - a/tools/check/check_sdl | 27 - a/tools/xenfb/Makefile | 32 - a/tools/xenfb/sdlfb.c | 342 ---------------- a/tools/xenfb/vncfb.c | 522 ------------------------ a/tools/xenfb/xenfb.c | 825 --------------------------------------- a/tools/xenfb/xenfb.h | 39 - b/tools/ioemu/hw/xenfb.c | 825 +++++++++++++++++++++++++++++++++++++++ b/tools/ioemu/hw/xenfb.h | 39 + tools/Makefile | 1 tools/check/Makefile | 4 tools/ioemu/Makefile.target | 2 tools/ioemu/hw/xen_machine_pv.c | 2 14 files changed, 868 insertions(+), 1831 deletions(-) Signed-off-by: Daniel P. Berrange <berrange@redhat.com> Dan. diff -r 450e0143acaf Config.mk --- a/Config.mk Tue Aug 14 14:31:01 2007 -0400 +++ b/Config.mk Tue Aug 14 14:35:18 2007 -0400 @@ -85,7 +85,6 @@ XENSTAT_XENTOP ?= y XENSTAT_XENTOP ?= y VTPM_TOOLS ?= n LIBXENAPI_BINDINGS ?= n -XENFB_TOOLS ?= n PYTHON_TOOLS ?= y -include $(XEN_ROOT)/.config diff -r 450e0143acaf tools/Makefile --- a/tools/Makefile Tue Aug 14 14:31:01 2007 -0400 +++ b/tools/Makefile Tue Aug 14 14:34:30 2007 -0400 @@ -19,7 +19,6 @@ SUBDIRS-y += libaio SUBDIRS-y += libaio SUBDIRS-y += blktap SUBDIRS-y += libfsimage -SUBDIRS-$(XENFB_TOOLS) += xenfb SUBDIRS-$(LIBXENAPI_BINDINGS) += libxen # These don''t cross-compile diff -r 450e0143acaf tools/check/Makefile --- a/tools/check/Makefile Tue Aug 14 14:31:01 2007 -0400 +++ b/tools/check/Makefile Tue Aug 14 14:37:27 2007 -0400 @@ -7,7 +7,7 @@ all: build # Check this machine is OK for building on. .PHONY: build build: - XENFB_TOOLS=$(XENFB_TOOLS) LIBXENAPI_BINDINGS=$(LIBXENAPI_BINDINGS) ./chk build + LIBXENAPI_BINDINGS=$(LIBXENAPI_BINDINGS) ./chk build # Check this machine is OK for installing on. # DO NOT use this check from ''make install'' in the parent @@ -15,7 +15,7 @@ build: # copy rather than actually installing. .PHONY: install install: - XENFB_TOOLS=$(XENFB_TOOLS) LIBXENAPI_BINDINGS=$(LIBXENAPI_BINDINGS) ./chk install + LIBXENAPI_BINDINGS=$(LIBXENAPI_BINDINGS) ./chk install .PHONY: clean clean: diff -r 450e0143acaf tools/check/check_libvncserver --- a/tools/check/check_libvncserver Tue Aug 14 14:31:01 2007 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -#!/bin/sh -# CHECK-BUILD CHECK-INSTALL - -if [ ! "$XENFB_TOOLS" = "y" ] -then - echo -n "unused, " - exit 0 -fi - -RC=0 - -LIBVNCSERVER_CONFIG="$(which libvncserver-config)" -tmpfile=$(mktemp) - -if test -z ${LIBVNCSERVER_CONFIG}; then - RC=1 -else - ${LIBVNCSERVER_CONFIG} --libs 2>&1 > /dev/null - RC=$? -fi - -if test $RC -ne 0; then - echo "FAILED" - echo " *** libvncserver-config is missing. " - echo " *** Please install libvncserver." -elif ! ld $($LIBVNCSERVER_CONFIG --libs) -o $tmpfile >/dev/null 2>&1; then - echo "FAILED" - echo " *** dependency libraries for libvncserver are missing: " - RC=1 - for i in $(ld $($LIBVNCSERVER_CONFIG --libs) -o $tmpfile 2>&1 >/dev/null); do - case $i in - -l*) echo lib${i#-l} - esac - done -fi -rm -f $tmpfile - -exit $RC diff -r 450e0143acaf tools/check/check_sdl --- a/tools/check/check_sdl Tue Aug 14 14:31:01 2007 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -#!/bin/sh -# CHECK-BUILD CHECK-INSTALL - -if [ ! "$XENFB_TOOLS" = "y" ] -then - echo -n "unused, " - exit 0 -fi - -RC=0 - -SDL_CONFIG="$(which sdl-config)" - -if test -z ${SDL_CONFIG}; then - RC=1 -else - ${SDL_CONFIG} --libs 2>&1 > /dev/null - RC=$? -fi - -if test $RC -ne 0; then - echo "FAILED" - echo " *** sdl-config is missing. " - echo " *** Please install libsdl-dev or sdl." -fi - -exit $RC diff -r 450e0143acaf tools/ioemu/Makefile.target --- a/tools/ioemu/Makefile.target Tue Aug 14 14:31:01 2007 -0400 +++ b/tools/ioemu/Makefile.target Tue Aug 14 14:35:38 2007 -0400 @@ -402,7 +402,7 @@ VL_OBJS+= xen_platform.o VL_OBJS+= xen_platform.o VL_OBJS+= xen_machine_fv.o VL_OBJS+= xen_machine_pv.o -VL_OBJS+= ../../xenfb/xenfb.o +VL_OBJS+= xenfb.o VL_OBJS+= tpm_tis.o CPPFLAGS += -DHAS_AUDIO endif diff -r 450e0143acaf tools/ioemu/hw/xen_machine_pv.c --- a/tools/ioemu/hw/xen_machine_pv.c Tue Aug 14 14:31:01 2007 -0400 +++ b/tools/ioemu/hw/xen_machine_pv.c Tue Aug 14 14:35:58 2007 -0400 @@ -23,7 +23,7 @@ */ #include "vl.h" -#include "../../xenfb/xenfb.h" +#include "xenfb.h" #include <linux/input.h> /* A convenient function for munging pixels between different depths */ diff -r 450e0143acaf tools/ioemu/hw/xenfb.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/ioemu/hw/xenfb.c Tue Aug 14 14:33:37 2007 -0400 @@ -0,0 +1,825 @@ +#include <stdarg.h> +#include <stdlib.h> +#include <sys/types.h> +#include <fcntl.h> +#include <unistd.h> +#include <xenctrl.h> +#include <xen/io/xenbus.h> +#include <xen/io/fbif.h> +#include <xen/io/kbdif.h> +#include <xen/io/protocols.h> +#include <sys/select.h> +#include <stdbool.h> +#include <xen/event_channel.h> +#include <sys/mman.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <xs.h> + +#include "xenfb.h" + +// FIXME defend against malicious frontend? + +struct xenfb_device { + const char *devicetype; + char nodename[64]; /* backend xenstore dir */ + char otherend[64]; /* frontend xenstore dir */ + int otherend_id; /* frontend domid */ + enum xenbus_state state; /* backend state */ + void *page; /* shared page */ + evtchn_port_t port; + struct xenfb_private *xenfb; +}; + +struct xenfb_private { + struct xenfb pub; + int evt_xch; /* event channel driver handle */ + int xc; /* hypervisor interface handle */ + struct xs_handle *xsh; /* xs daemon handle */ + struct xenfb_device fb, kbd; + size_t fb_len; /* size of framebuffer */ + char protocol[64]; /* frontend protocol */ +}; + +static void xenfb_detach_dom(struct xenfb_private *); + +static char *xenfb_path_in_dom(struct xs_handle *xsh, + char *buf, size_t size, + unsigned domid, const char *fmt, ...) +{ + va_list ap; + char *domp = xs_get_domain_path(xsh, domid); + int n; + + if (domp == NULL) + return NULL; + + n = snprintf(buf, size, "%s/", domp); + free(domp); + if (n >= size) + return NULL; + + va_start(ap, fmt); + n += vsnprintf(buf + n, size - n, fmt, ap); + va_end(ap); + if (n >= size) + return NULL; + + return buf; +} + +static int xenfb_xs_scanf1(struct xs_handle *xsh, + const char *dir, const char *node, + const char *fmt, void *dest) +{ + char buf[1024]; + char *p; + int ret; + + if (snprintf(buf, sizeof(buf), "%s/%s", dir, node) >= sizeof(buf)) { + errno = ENOENT; + return -1; + } + p = xs_read(xsh, XBT_NULL, buf, NULL); + if (!p) { + errno = ENOENT; + return -1; + } + ret = sscanf(p, fmt, dest); + free(p); + if (ret != 1) { + errno = EDOM; + return -1; + } + return ret; +} + +static int xenfb_xs_printf(struct xs_handle *xsh, + const char *dir, const char *node, char *fmt, ...) +{ + va_list ap; + char key[1024]; + char val[1024]; + int n; + + if (snprintf(key, sizeof(key), "%s/%s", dir, node) >= sizeof(key)) { + errno = ENOENT; + return -1; + } + + va_start(ap, fmt); + n = vsnprintf(val, sizeof(val), fmt, ap); + va_end(ap); + if (n >= sizeof(val)) { + errno = ENOSPC; /* close enough */ + return -1; + } + + if (!xs_write(xsh, XBT_NULL, key, val, n)) + return -1; + return 0; +} + +static void xenfb_device_init(struct xenfb_device *dev, + const char *type, + struct xenfb_private *xenfb) +{ + dev->devicetype = type; + dev->otherend_id = -1; + dev->port = -1; + dev->xenfb = xenfb; +} + +int xenfb_device_set_domain(struct xenfb_device *dev, int domid) +{ + struct xenfb_private *xenfb = dev->xenfb; + + dev->otherend_id = domid; + + if (!xenfb_path_in_dom(xenfb->xsh, + dev->otherend, sizeof(dev->otherend), + domid, "device/%s/0", dev->devicetype)) { + errno = ENOENT; + return -1; + } + if (!xenfb_path_in_dom(xenfb->xsh, + dev->nodename, sizeof(dev->nodename), + 0, "backend/%s/%d/0", dev->devicetype, domid)) { + errno = ENOENT; + return -1; + } + + return 0; +} + +struct xenfb *xenfb_new(void) +{ + struct xenfb_private *xenfb = malloc(sizeof(*xenfb)); + int serrno; + + if (xenfb == NULL) + return NULL; + + memset(xenfb, 0, sizeof(*xenfb)); + xenfb->evt_xch = xenfb->xc = -1; + xenfb_device_init(&xenfb->fb, "vfb", xenfb); + xenfb_device_init(&xenfb->kbd, "vkbd", xenfb); + + xenfb->evt_xch = xc_evtchn_open(); + if (xenfb->evt_xch == -1) + goto fail; + + xenfb->xc = xc_interface_open(); + if (xenfb->xc == -1) + goto fail; + + xenfb->xsh = xs_daemon_open(); + if (!xenfb->xsh) + goto fail; + + return &xenfb->pub; + + fail: + serrno = errno; + xenfb_delete(&xenfb->pub); + errno = serrno; + return NULL; +} + +/* Remove the backend area in xenbus since the framebuffer really is + going away. */ +void xenfb_teardown(struct xenfb *xenfb_pub) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + + xs_rm(xenfb->xsh, XBT_NULL, xenfb->fb.nodename); + xs_rm(xenfb->xsh, XBT_NULL, xenfb->kbd.nodename); +} + + +void xenfb_delete(struct xenfb *xenfb_pub) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + + xenfb_detach_dom(xenfb); + if (xenfb->xc >= 0) + xc_interface_close(xenfb->xc); + if (xenfb->evt_xch >= 0) + xc_evtchn_close(xenfb->evt_xch); + if (xenfb->xsh) + xs_daemon_close(xenfb->xsh); + free(xenfb); +} + +static enum xenbus_state xenfb_read_state(struct xs_handle *xsh, + const char *dir) +{ + int ret, state; + + ret = xenfb_xs_scanf1(xsh, dir, "state", "%d", &state); + if (ret < 0) + return XenbusStateUnknown; + + if ((unsigned)state > XenbusStateClosed) + state = XenbusStateUnknown; + return state; +} + +static int xenfb_switch_state(struct xenfb_device *dev, + enum xenbus_state state) +{ + struct xs_handle *xsh = dev->xenfb->xsh; + + if (xenfb_xs_printf(xsh, dev->nodename, "state", "%d", state) < 0) + return -1; + dev->state = state; + return 0; +} + +static int xenfb_wait_for_state(struct xs_handle *xsh, const char *dir, + unsigned awaited) +{ + unsigned state, dummy; + char **vec; + + awaited |= 1 << XenbusStateUnknown; + + for (;;) { + state = xenfb_read_state(xsh, dir); + if ((1 << state) & awaited) + return state; + + vec = xs_read_watch(xsh, &dummy); + if (!vec) + return -1; + free(vec); + } +} + +static int xenfb_wait_for_backend_creation(struct xenfb_device *dev) +{ + struct xs_handle *xsh = dev->xenfb->xsh; + int state; + + if (!xs_watch(xsh, dev->nodename, "")) + return -1; + state = xenfb_wait_for_state(xsh, dev->nodename, + (1 << XenbusStateInitialising) + | (1 << XenbusStateClosed) +#if 1 /* TODO fudging state to permit restarting; to be removed */ + | (1 << XenbusStateInitWait) + | (1 << XenbusStateConnected) + | (1 << XenbusStateClosing) +#endif + ); + xs_unwatch(xsh, dev->nodename, ""); + + switch (state) { +#if 1 + case XenbusStateInitWait: + case XenbusStateConnected: + printf("Fudging state to %d\n", XenbusStateInitialising); /* FIXME */ +#endif + case XenbusStateInitialising: + case XenbusStateClosing: + case XenbusStateClosed: + break; + default: + return -1; + } + + return 0; +} + +static int xenfb_hotplug(struct xenfb_device *dev) +{ + if (xenfb_xs_printf(dev->xenfb->xsh, dev->nodename, + "hotplug-status", "connected")) + return -1; + return 0; +} + +static int xenfb_wait_for_frontend_initialised(struct xenfb_device *dev) +{ + switch (xenfb_wait_for_state(dev->xenfb->xsh, dev->otherend, +#if 1 /* TODO fudging state to permit restarting; to be removed */ + (1 << XenbusStateInitialised) + | (1 << XenbusStateConnected) +#else + 1 << XenbusStateInitialised, +#endif + )) { +#if 1 + case XenbusStateConnected: + printf("Fudging state to %d\n", XenbusStateInitialised); /* FIXME */ +#endif + case XenbusStateInitialised: + break; + default: + return -1; + } + + return 0; +} + +static void xenfb_copy_mfns(int mode, int count, unsigned long *dst, void *src) +{ + uint32_t *src32 = src; + uint64_t *src64 = src; + int i; + + for (i = 0; i < count; i++) + dst[i] = (mode == 32) ? src32[i] : src64[i]; +} + +static int xenfb_map_fb(struct xenfb_private *xenfb, int domid) +{ + struct xenfb_page *page = xenfb->fb.page; + int n_fbmfns; + int n_fbdirs; + unsigned long *pgmfns = NULL; + unsigned long *fbmfns = NULL; + void *map, *pd; + int mode, ret = -1; + + /* default to native */ + pd = page->pd; + mode = sizeof(unsigned long) * 8; + + if (0 == strlen(xenfb->protocol)) { + /* + * Undefined protocol, some guesswork needed. + * + * Old frontends which don''t set the protocol use + * one page directory only, thus pd[1] must be zero. + * pd[1] of the 32bit struct layout and the lower + * 32 bits of pd[0] of the 64bit struct layout have + * the same location, so we can check that ... + */ + uint32_t *ptr32 = NULL; + uint32_t *ptr64 = NULL; +#if defined(__i386__) + ptr32 = (void*)page->pd; + ptr64 = ((void*)page->pd) + 4; +#elif defined(__x86_64__) + ptr32 = ((void*)page->pd) - 4; + ptr64 = (void*)page->pd; +#endif + if (ptr32) { + if (0 == ptr32[1]) { + mode = 32; + pd = ptr32; + } else { + mode = 64; + pd = ptr64; + } + } +#if defined(__x86_64__) + } else if (0 == strcmp(xenfb->protocol, XEN_IO_PROTO_ABI_X86_32)) { + /* 64bit dom0, 32bit domU */ + mode = 32; + pd = ((void*)page->pd) - 4; +#elif defined(__i386__) + } else if (0 == strcmp(xenfb->protocol, XEN_IO_PROTO_ABI_X86_64)) { + /* 32bit dom0, 64bit domU */ + mode = 64; + pd = ((void*)page->pd) + 4; +#endif + } + + n_fbmfns = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE; + n_fbdirs = n_fbmfns * mode / 8; + n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE; + + pgmfns = malloc(sizeof(unsigned long) * n_fbdirs); + fbmfns = malloc(sizeof(unsigned long) * n_fbmfns); + if (!pgmfns || !fbmfns) + goto out; + + /* + * Bug alert: xc_map_foreign_batch() can fail partly and + * return a non-null value. This is a design flaw. When it + * happens, we happily continue here, and later crash on + * access. + */ + xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd); + map = xc_map_foreign_batch(xenfb->xc, domid, + PROT_READ, pgmfns, n_fbdirs); + if (map == NULL) + goto out; + xenfb_copy_mfns(mode, n_fbmfns, fbmfns, map); + munmap(map, n_fbdirs * XC_PAGE_SIZE); + + xenfb->pub.pixels = xc_map_foreign_batch(xenfb->xc, domid, + PROT_READ | PROT_WRITE, fbmfns, n_fbmfns); + if (xenfb->pub.pixels == NULL) + goto out; + + ret = 0; /* all is fine */ + + out: + if (pgmfns) + free(pgmfns); + if (fbmfns) + free(fbmfns); + return ret; +} + +static int xenfb_bind(struct xenfb_device *dev) +{ + struct xenfb_private *xenfb = dev->xenfb; + unsigned long mfn; + evtchn_port_t evtchn; + + if (xenfb_xs_scanf1(xenfb->xsh, dev->otherend, "page-ref", "%lu", + &mfn) < 0) + return -1; + if (xenfb_xs_scanf1(xenfb->xsh, dev->otherend, "event-channel", "%u", + &evtchn) < 0) + return -1; + + dev->port = xc_evtchn_bind_interdomain(xenfb->evt_xch, + dev->otherend_id, evtchn); + if (dev->port == -1) + return -1; + + dev->page = xc_map_foreign_range(xenfb->xc, dev->otherend_id, + XC_PAGE_SIZE, PROT_READ | PROT_WRITE, mfn); + if (dev->page == NULL) + return -1; + + return 0; +} + +static void xenfb_unbind(struct xenfb_device *dev) +{ + if (dev->page) { + munmap(dev->page, XC_PAGE_SIZE); + dev->page = NULL; + } + if (dev->port >= 0) { + xc_evtchn_unbind(dev->xenfb->evt_xch, dev->port); + dev->port = -1; + } +} + +static int xenfb_wait_for_frontend_connected(struct xenfb_device *dev) +{ + switch (xenfb_wait_for_state(dev->xenfb->xsh, dev->otherend, + 1 << XenbusStateConnected)) { + case XenbusStateConnected: + break; + default: + return -1; + } + + return 0; +} + +static void xenfb_dev_fatal(struct xenfb_device *dev, int err, + const char *fmt, ...) +{ + struct xs_handle *xsh = dev->xenfb->xsh; + va_list ap; + char errdir[80]; + char buf[1024]; + int n; + + fprintf(stderr, "%s ", dev->nodename); /* somewhat crude */ + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + if (err) + fprintf(stderr, " (%s)", strerror(err)); + putc(''\n'', stderr); + + if (!xenfb_path_in_dom(xsh, errdir, sizeof(errdir), 0, + "error/%s", dev->nodename)) + goto out; /* FIXME complain */ + + va_start(ap, fmt); + n = snprintf(buf, sizeof(buf), "%d ", err); + snprintf(buf + n, sizeof(buf) - n, fmt, ap); + va_end(ap); + + if (xenfb_xs_printf(xsh, buf, "error", "%s", buf) < 0) + goto out; /* FIXME complain */ + + out: + xenfb_switch_state(dev, XenbusStateClosing); +} + +int xenfb_attach_dom(struct xenfb *xenfb_pub, int domid) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + struct xs_handle *xsh = xenfb->xsh; + int val, serrno; + struct xenfb_page *fb_page; + + xenfb_detach_dom(xenfb); + + xenfb_device_set_domain(&xenfb->fb, domid); + xenfb_device_set_domain(&xenfb->kbd, domid); + + if (xenfb_wait_for_backend_creation(&xenfb->fb) < 0) + goto error; + if (xenfb_wait_for_backend_creation(&xenfb->kbd) < 0) + goto error; + + if (xenfb_xs_printf(xsh, xenfb->kbd.nodename, "feature-abs-pointer", "1")) + goto error; + if (xenfb_switch_state(&xenfb->fb, XenbusStateInitWait)) + goto error; + if (xenfb_switch_state(&xenfb->kbd, XenbusStateInitWait)) + goto error; + + if (xenfb_hotplug(&xenfb->fb) < 0) + goto error; + if (xenfb_hotplug(&xenfb->kbd) < 0) + goto error; + + if (!xs_watch(xsh, xenfb->fb.otherend, "")) + goto error; + if (!xs_watch(xsh, xenfb->kbd.otherend, "")) + goto error; + + if (xenfb_wait_for_frontend_initialised(&xenfb->fb) < 0) + goto error; + if (xenfb_wait_for_frontend_initialised(&xenfb->kbd) < 0) + goto error; + + if (xenfb_bind(&xenfb->fb) < 0) + goto error; + if (xenfb_bind(&xenfb->kbd) < 0) + goto error; + + if (xenfb_xs_scanf1(xsh, xenfb->fb.otherend, "feature-update", + "%d", &val) < 0) + val = 0; + if (!val) { + errno = ENOTSUP; + goto error; + } + if (xenfb_xs_scanf1(xsh, xenfb->fb.otherend, "protocol", "%63s", + xenfb->protocol) < 0) + xenfb->protocol[0] = ''\0''; + xenfb_xs_printf(xsh, xenfb->fb.nodename, "request-update", "1"); + + /* TODO check for permitted ranges */ + fb_page = xenfb->fb.page; + xenfb->pub.depth = fb_page->depth; + xenfb->pub.width = fb_page->width; + xenfb->pub.height = fb_page->height; + /* TODO check for consistency with the above */ + xenfb->fb_len = fb_page->mem_length; + xenfb->pub.row_stride = fb_page->line_length; + + if (xenfb_map_fb(xenfb, domid) < 0) + goto error; + + if (xenfb_switch_state(&xenfb->fb, XenbusStateConnected)) + goto error; + if (xenfb_switch_state(&xenfb->kbd, XenbusStateConnected)) + goto error; + + if (xenfb_wait_for_frontend_connected(&xenfb->kbd) < 0) + goto error; + if (xenfb_xs_scanf1(xsh, xenfb->kbd.otherend, "request-abs-pointer", + "%d", &val) < 0) + val = 0; + xenfb->pub.abs_pointer_wanted = val; + + return 0; + + error: + serrno = errno; + xenfb_detach_dom(xenfb); + xenfb_dev_fatal(&xenfb->fb, serrno, "on fire"); + xenfb_dev_fatal(&xenfb->kbd, serrno, "on fire"); + errno = serrno; + return -1; +} + +static void xenfb_detach_dom(struct xenfb_private *xenfb) +{ + xenfb_unbind(&xenfb->fb); + xenfb_unbind(&xenfb->kbd); + if (xenfb->pub.pixels) { + munmap(xenfb->pub.pixels, xenfb->fb_len); + xenfb->pub.pixels = NULL; + } +} + +static void xenfb_on_fb_event(struct xenfb_private *xenfb) +{ + uint32_t prod, cons; + struct xenfb_page *page = xenfb->fb.page; + + prod = page->out_prod; + if (prod == page->out_cons) + return; + rmb(); /* ensure we see ring contents up to prod */ + for (cons = page->out_cons; cons != prod; cons++) { + union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons); + + switch (event->type) { + case XENFB_TYPE_UPDATE: + if (xenfb->pub.update) + xenfb->pub.update(&xenfb->pub, + event->update.x, event->update.y, + event->update.width, event->update.height); + break; + } + } + mb(); /* ensure we''re done with ring contents */ + page->out_cons = cons; + xc_evtchn_notify(xenfb->evt_xch, xenfb->fb.port); +} + +static void xenfb_on_kbd_event(struct xenfb_private *xenfb) +{ + struct xenkbd_page *page = xenfb->kbd.page; + + /* We don''t understand any keyboard events, so just ignore them. */ + if (page->out_prod == page->out_cons) + return; + page->out_cons = page->out_prod; + xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port); +} + +static int xenfb_on_state_change(struct xenfb_device *dev) +{ + enum xenbus_state state; + + state = xenfb_read_state(dev->xenfb->xsh, dev->otherend); + + switch (state) { + case XenbusStateUnknown: + /* There was an error reading the frontend state. The + domain has probably gone away; in any case, there''s + not much point in us continuing. */ + return -1; + case XenbusStateInitialising: + case XenbusStateInitWait: + case XenbusStateInitialised: + case XenbusStateConnected: + break; + case XenbusStateClosing: + xenfb_unbind(dev); + xenfb_switch_state(dev, state); + break; + case XenbusStateClosed: + xenfb_switch_state(dev, state); + } + return 0; +} + +int xenfb_dispatch_channel(struct xenfb *xenfb_pub) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + evtchn_port_t port; + port = xc_evtchn_pending(xenfb->evt_xch); + if (port == -1) + return -1; + + if (port == xenfb->fb.port) + xenfb_on_fb_event(xenfb); + else if (port == xenfb->kbd.port) + xenfb_on_kbd_event(xenfb); + + if (xc_evtchn_unmask(xenfb->evt_xch, port) == -1) + return -1; + + return 0; +} + +int xenfb_dispatch_store(struct xenfb *xenfb_pub) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + unsigned dummy; + char **vec; + int r; + + vec = xs_read_watch(xenfb->xsh, &dummy); + free(vec); + r = xenfb_on_state_change(&xenfb->fb); + if (r == 0) + r = xenfb_on_state_change(&xenfb->kbd); + if (r == -1) + return -2; + + return 0; +} + + +/* Returns 0 normally, -1 on error, or -2 if the domain went away. */ +int xenfb_poll(struct xenfb *xenfb_pub, fd_set *readfds) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + int ret; + + if (FD_ISSET(xc_evtchn_fd(xenfb->evt_xch), readfds)) { + if ((ret = xenfb_dispatch_channel(xenfb_pub)) < 0) + return ret; + } + + if (FD_ISSET(xs_fileno(xenfb->xsh), readfds)) { + if ((ret = xenfb_dispatch_store(xenfb_pub)) < 0) + return ret; + } + + return 0; +} + +int xenfb_select_fds(struct xenfb *xenfb_pub, fd_set *readfds) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + int fd1 = xc_evtchn_fd(xenfb->evt_xch); + int fd2 = xs_fileno(xenfb->xsh); + + FD_SET(fd1, readfds); + FD_SET(fd2, readfds); + return fd1 > fd2 ? fd1 + 1 : fd2 + 1; +} + +int xenfb_get_store_fd(struct xenfb *xenfb_pub) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + return xs_fileno(xenfb->xsh); +} + +int xenfb_get_channel_fd(struct xenfb *xenfb_pub) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + return xc_evtchn_fd(xenfb->evt_xch); +} + +static int xenfb_kbd_event(struct xenfb_private *xenfb, + union xenkbd_in_event *event) +{ + uint32_t prod; + struct xenkbd_page *page = xenfb->kbd.page; + + if (xenfb->kbd.state != XenbusStateConnected) + return 0; + + prod = page->in_prod; + if (prod - page->in_cons == XENKBD_IN_RING_LEN) { + errno = EAGAIN; + return -1; + } + + mb(); /* ensure ring space available */ + XENKBD_IN_RING_REF(page, prod) = *event; + wmb(); /* ensure ring contents visible */ + page->in_prod = prod + 1; + return xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port); +} + +int xenfb_send_key(struct xenfb *xenfb_pub, bool down, int keycode) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + union xenkbd_in_event event; + + memset(&event, 0, XENKBD_IN_EVENT_SIZE); + event.type = XENKBD_TYPE_KEY; + event.key.pressed = down ? 1 : 0; + event.key.keycode = keycode; + + return xenfb_kbd_event(xenfb, &event); +} + +int xenfb_send_motion(struct xenfb *xenfb_pub, int rel_x, int rel_y) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + union xenkbd_in_event event; + + memset(&event, 0, XENKBD_IN_EVENT_SIZE); + event.type = XENKBD_TYPE_MOTION; + event.motion.rel_x = rel_x; + event.motion.rel_y = rel_y; + + return xenfb_kbd_event(xenfb, &event); +} + +int xenfb_send_position(struct xenfb *xenfb_pub, int abs_x, int abs_y) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + union xenkbd_in_event event; + + memset(&event, 0, XENKBD_IN_EVENT_SIZE); + event.type = XENKBD_TYPE_POS; + event.pos.abs_x = abs_x; + event.pos.abs_y = abs_y; + + return xenfb_kbd_event(xenfb, &event); +} +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff -r 450e0143acaf tools/ioemu/hw/xenfb.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/ioemu/hw/xenfb.h Tue Aug 14 14:33:40 2007 -0400 @@ -0,0 +1,39 @@ +#ifndef _XENFB_H_ +#define _XENFB_H_ + +#include <stdbool.h> +#include <sys/types.h> + +struct xenfb +{ + void *pixels; + + int row_stride; + int depth; + int width; + int height; + int abs_pointer_wanted; + + void *user_data; + + void (*update)(struct xenfb *xenfb, int x, int y, int width, int height); +}; + +struct xenfb *xenfb_new(void); +void xenfb_delete(struct xenfb *xenfb); +void xenfb_teardown(struct xenfb *xenfb); + +int xenfb_attach_dom(struct xenfb *xenfb, int domid); + +int xenfb_dispatch_store(struct xenfb *xenfb_pub); +int xenfb_dispatch_channel(struct xenfb *xenfb_pub); +int xenfb_select_fds(struct xenfb *xenfb, fd_set *readfds); +int xenfb_poll(struct xenfb *xenfb, fd_set *readfds); +int xenfb_get_store_fd(struct xenfb *xenfb_pub); +int xenfb_get_channel_fd(struct xenfb *xenfb_pub); + +int xenfb_send_key(struct xenfb *xenfb, bool down, int keycode); +int xenfb_send_motion(struct xenfb *xenfb, int rel_x, int rel_y); +int xenfb_send_position(struct xenfb *xenfb, int abs_x, int abs_y); + +#endif diff -r 450e0143acaf tools/xenfb/Makefile --- a/tools/xenfb/Makefile Tue Aug 14 14:31:01 2007 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -XEN_ROOT=../.. -include $(XEN_ROOT)/tools/Rules.mk - -CFLAGS += -I$(XEN_LIBXC) -I$(XEN_XENSTORE) -CFLAGS += -I$(XEN_ROOT)/tools/ioemu -LDFLAGS += -L$(XEN_LIBXC) -L$(XEN_XENSTORE) - -.PHONY: all -all: build - -.PHONY: build -build: - $(MAKE) vncfb sdlfb - -install: all - $(INSTALL_DIR) $(DESTDIR)/usr/$(LIBDIR)/xen/bin - $(INSTALL_PROG) vncfb $(DESTDIR)/usr/$(LIBDIR)/xen/bin/xen-vncfb - $(INSTALL_PROG) sdlfb $(DESTDIR)/usr/$(LIBDIR)/xen/bin/xen-sdlfb - -sdlfb: sdlfb.o xenfb.o - -sdlfb.o: CFLAGS += $(shell sdl-config --cflags) -sdlfb: LDLIBS += $(shell sdl-config --libs) -lxenctrl -lxenstore - -clean: - $(RM) *.o *~ vncfb sdlfb - -vncfb: vncfb.o xenfb.o -vncfb.o: CFLAGS += $(shell libvncserver-config --cflags) -vncfb: LDLIBS += $(shell libvncserver-config --libs) -lxenctrl -lxenstore - -sdlfb.o xenfb.o vncfb.o: xenfb.h diff -r 450e0143acaf tools/xenfb/sdlfb.c --- a/tools/xenfb/sdlfb.c Tue Aug 14 14:31:01 2007 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,342 +0,0 @@ -#include <SDL.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/select.h> -#include <stdlib.h> -#include <linux/input.h> -#include <getopt.h> -#include <string.h> -#include "xenfb.h" - -struct SDLFBData -{ - SDL_Surface *dst; - SDL_Surface *src; -}; - -/* - * Map from scancode to Linux input layer keycode. Scancodes are - * hardware-specific. This map assumes a standard AT or PS/2 - * keyboard. - * - * Why use scancodes? We can''t use key symbols, because they don''t - * identify keys --- they''re what keys are mapped to. The standard - * German keymap, for instance, maps both KEY_COMMA and KEY_102ND to - * SDLK_LESS. - */ -static int keymap[256] = { - [9] = KEY_ESC, - [10] = KEY_1, - [11] = KEY_2, - [12] = KEY_3, - [13] = KEY_4, - [14] = KEY_5, - [15] = KEY_6, - [16] = KEY_7, - [17] = KEY_8, - [18] = KEY_9, - [19] = KEY_0, - [20] = KEY_MINUS, - [21] = KEY_EQUAL, - [22] = KEY_BACKSPACE, - [23] = KEY_TAB, - [24] = KEY_Q, - [25] = KEY_W, - [26] = KEY_E, - [27] = KEY_R, - [28] = KEY_T, - [29] = KEY_Y, - [30] = KEY_U, - [31] = KEY_I, - [32] = KEY_O, - [33] = KEY_P, - [34] = KEY_LEFTBRACE, - [35] = KEY_RIGHTBRACE, - [36] = KEY_ENTER, - [37] = KEY_LEFTCTRL, - [38] = KEY_A, - [39] = KEY_S, - [40] = KEY_D, - [41] = KEY_F, - [42] = KEY_G, - [43] = KEY_H, - [44] = KEY_J, - [45] = KEY_K, - [46] = KEY_L, - [47] = KEY_SEMICOLON, - [48] = KEY_APOSTROPHE, - [49] = KEY_GRAVE, - [50] = KEY_LEFTSHIFT, - [51] = KEY_BACKSLASH, - [52] = KEY_Z, - [53] = KEY_X, - [54] = KEY_C, - [55] = KEY_V, - [56] = KEY_B, - [57] = KEY_N, - [58] = KEY_M, - [59] = KEY_COMMA, - [60] = KEY_DOT, - [61] = KEY_SLASH, - [62] = KEY_RIGHTSHIFT, - [63] = KEY_KPASTERISK, - [64] = KEY_LEFTALT, - [65] = KEY_SPACE, - [66] = KEY_CAPSLOCK, - [67] = KEY_F1, - [68] = KEY_F2, - [69] = KEY_F3, - [70] = KEY_F4, - [71] = KEY_F5, - [72] = KEY_F6, - [73] = KEY_F7, - [74] = KEY_F8, - [75] = KEY_F9, - [76] = KEY_F10, - [77] = KEY_NUMLOCK, - [78] = KEY_SCROLLLOCK, - [79] = KEY_KP7, - [80] = KEY_KP8, - [81] = KEY_KP9, - [82] = KEY_KPMINUS, - [83] = KEY_KP4, - [84] = KEY_KP5, - [85] = KEY_KP6, - [86] = KEY_KPPLUS, - [87] = KEY_KP1, - [88] = KEY_KP2, - [89] = KEY_KP3, - [90] = KEY_KP0, - [91] = KEY_KPDOT, - [94] = KEY_102ND, /* FIXME is this correct? */ - [95] = KEY_F11, - [96] = KEY_F12, - [108] = KEY_KPENTER, - [109] = KEY_RIGHTCTRL, - [112] = KEY_KPSLASH, - [111] = KEY_SYSRQ, - [113] = KEY_RIGHTALT, - [97] = KEY_HOME, - [98] = KEY_UP, - [99] = KEY_PAGEUP, - [100] = KEY_LEFT, - [102] = KEY_RIGHT, - [103] = KEY_END, - [104] = KEY_DOWN, - [105] = KEY_PAGEDOWN, - [106] = KEY_INSERT, - [107] = KEY_DELETE, - [110] = KEY_PAUSE, - [115] = KEY_LEFTMETA, - [116] = KEY_RIGHTMETA, - [117] = KEY_MENU, -}; - -static int btnmap[] = { - [SDL_BUTTON_LEFT] = BTN_LEFT, - [SDL_BUTTON_MIDDLE] = BTN_MIDDLE, - [SDL_BUTTON_RIGHT] = BTN_RIGHT, - /* FIXME not 100% sure about these: */ - [SDL_BUTTON_WHEELUP] = BTN_FORWARD, - [SDL_BUTTON_WHEELDOWN] BTN_BACK -}; - -static void sdl_update(struct xenfb *xenfb, int x, int y, int width, int height) -{ - struct SDLFBData *data = xenfb->user_data; - SDL_Rect r = { x, y, width, height }; - SDL_BlitSurface(data->src, &r, data->dst, &r); - SDL_UpdateRect(data->dst, x, y, width, height); -} - -static int sdl_on_event(struct xenfb *xenfb, SDL_Event *event) -{ - int x, y, ret; - - switch (event->type) { - case SDL_KEYDOWN: - case SDL_KEYUP: - if (keymap[event->key.keysym.scancode] == 0) - break; - ret = xenfb_send_key(xenfb, - event->type == SDL_KEYDOWN, - keymap[event->key.keysym.scancode]); - if (ret < 0) - fprintf(stderr, "Key %d %s lost (%s)\n", - keymap[event->key.keysym.scancode], - event->type == SDL_KEYDOWN ? "down" : "up", - strerror(errno)); - break; - case SDL_MOUSEMOTION: - if (xenfb->abs_pointer_wanted) { - SDL_GetMouseState(&x, &y); - ret = xenfb_send_position(xenfb, x, y); - } else { - SDL_GetRelativeMouseState(&x, &y); - ret = xenfb_send_motion(xenfb, x, y); - } - if (ret < 0) - fprintf(stderr, "Pointer to %d,%d lost (%s)\n", - x, y, strerror(errno)); - break; - case SDL_MOUSEBUTTONDOWN: - case SDL_MOUSEBUTTONUP: - if (event->button.button >= sizeof(btnmap) / sizeof(*btnmap)) - break; - if (btnmap[event->button.button] == 0) - break; - ret = xenfb_send_key(xenfb, - event->type == SDL_MOUSEBUTTONDOWN, - btnmap[event->button.button]); - if (ret < 0) - fprintf(stderr, "Button %d %s lost (%s)\n", - btnmap[event->button.button] - BTN_MOUSE, - event->type == SDL_MOUSEBUTTONDOWN ? "down" : "up", - strerror(errno)); - break; - case SDL_QUIT: - return 0; - } - - return 1; -} - -static struct option options[] = { - { "domid", 1, NULL, ''d'' }, - { "title", 1, NULL, ''t'' }, - { NULL } -}; - -int main(int argc, char **argv) -{ - struct xenfb *xenfb; - int domid = -1; - char * title = NULL; - fd_set readfds; - int nfds; - struct SDLFBData data; - SDL_Rect r; - struct timeval tv; - SDL_Event event; - int do_quit = 0; - int opt; - char *endp; - int retval; - - while ((opt = getopt_long(argc, argv, "d:t:", options, - NULL)) != -1) { - switch (opt) { - case ''d'': - domid = strtol(optarg, &endp, 10); - if (endp == optarg || *endp) { - fprintf(stderr, "Invalid domain id specified\n"); - exit(1); - } - break; - case ''t'': - title = strdup(optarg); - break; - case ''?'': - exit(1); - } - } - if (optind != argc) { - fprintf(stderr, "Invalid options!\n"); - exit(1); - } - if (domid <= 0) { - fprintf(stderr, "Domain ID must be specified!\n"); - exit(1); - } - - xenfb = xenfb_new(); - if (xenfb == NULL) { - fprintf(stderr, "Could not create framebuffer (%s)\n", - strerror(errno)); - exit(1); - } - - if (xenfb_attach_dom(xenfb, domid) < 0) { - fprintf(stderr, "Could not connect to domain (%s)\n", - strerror(errno)); - exit(1); - } - - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - fprintf(stderr, "Could not initialize SDL\n"); - exit(1); - } - - data.dst = SDL_SetVideoMode(xenfb->width, xenfb->height, xenfb->depth, - SDL_SWSURFACE); - if (!data.dst) { - fprintf(stderr, "SDL_SetVideoMode failed\n"); - exit(1); - } - - data.src = SDL_CreateRGBSurfaceFrom(xenfb->pixels, - xenfb->width, xenfb->height, - xenfb->depth, xenfb->row_stride, - 0xFF0000, 0xFF00, 0xFF, 0); - - if (!data.src) { - fprintf(stderr, "SDL_CreateRGBSurfaceFrom failed\n"); - exit(1); - } - - if (title == NULL) - title = strdup("xen-sdlfb"); - SDL_WM_SetCaption(title, title); - - r.x = r.y = 0; - r.w = xenfb->width; - r.h = xenfb->height; - SDL_BlitSurface(data.src, &r, data.dst, &r); - SDL_UpdateRect(data.dst, 0, 0, xenfb->width, xenfb->height); - - xenfb->update = sdl_update; - xenfb->user_data = &data; - - SDL_ShowCursor(0); - - /* - * We need to wait for fds becoming ready or SDL events to - * arrive. We time out the select after 10ms to poll for SDL - * events. Clunky, but works. Could avoid the clunkiness - * with a separate thread. - */ - for (;;) { - FD_ZERO(&readfds); - nfds = xenfb_select_fds(xenfb, &readfds); - tv = (struct timeval){0, 10000}; - - if (select(nfds, &readfds, NULL, NULL, &tv) < 0) { - if (errno == EINTR) - continue; - fprintf(stderr, - "Can''t select() on event channel (%s)\n", - strerror(errno)); - break; - } - - while (SDL_PollEvent(&event)) { - if (!sdl_on_event(xenfb, &event)) - do_quit = 1; - } - - if (do_quit) - break; - - retval = xenfb_poll(xenfb, &readfds); - if (retval == -2) - xenfb_teardown(xenfb); - if (retval < 0) - break; - } - - xenfb_delete(xenfb); - - SDL_Quit(); - - return 0; -} diff -r 450e0143acaf tools/xenfb/vncfb.c --- a/tools/xenfb/vncfb.c Tue Aug 14 14:31:01 2007 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,522 +0,0 @@ -#define _GNU_SOURCE -#include <errno.h> -#include <getopt.h> -#include <stdlib.h> -#include <signal.h> -#include <unistd.h> -#include <malloc.h> -#include <rfb/rfb.h> -#include <rfb/keysym.h> -#include <linux/input.h> -#include <xs.h> -#include "xenfb.h" - -/* Grab key translation support routines from qemu directory. */ -#define qemu_mallocz(size) calloc(1, (size)) -static const char *bios_dir = "/usr/share/xen/qemu"; -#include "vnc_keysym.h" -#include "keymaps.c" - -static unsigned char atkbd_set2_keycode[512] = { - - 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41,117, - 0, 56, 42, 93, 29, 16, 2, 0, 0, 0, 44, 31, 30, 17, 3, 0, - 0, 46, 45, 32, 18, 5, 4, 95, 0, 57, 47, 33, 20, 19, 6,183, - 0, 49, 48, 35, 34, 21, 7,184, 0, 0, 50, 36, 22, 8, 9,185, - 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0, - 0, 89, 40, 0, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 85, - 0, 86, 91, 90, 92, 0, 14, 94, 0, 79,124, 75, 71,121, 0, 0, - 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99, - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 217,100,255, 0, 97,165, 0, 0,156, 0, 0, 0, 0, 0, 0,125, - 173,114, 0,113, 0, 0, 0,126,128, 0, 0,140, 0, 0, 0,127, - 159, 0,115, 0,164, 0, 0,116,158, 0,150,166, 0, 0, 0,142, - 157, 0, 0, 0, 0, 0, 0, 0,155, 0, 98, 0, 0,163, 0, 0, - 226, 0, 0, 0, 0, 0, 0, 0, 0,255, 96, 0, 0, 0,143, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,107, 0,105,102, 0, 0,112, - 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119, 0, - -}; - -static unsigned char atkbd_unxlate_table[128] = { - - 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13, - 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27, - 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42, - 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3, - 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105, - 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63, - 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111, - 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110 - -}; - -unsigned char keycode_table[512]; - -static void *kbd_layout; -uint8_t modifiers_state[256]; - -static int btnmap[] = { - BTN_LEFT, BTN_MIDDLE, BTN_RIGHT, BTN_SIDE, - BTN_EXTRA, BTN_FORWARD, BTN_BACK, BTN_TASK -}; - -static void press_key_shift_down(struct xenfb* xenfb, int down, int scancode) -{ - if (down) - xenfb_send_key(xenfb, 1, keycode_table[0x2a]); - - if (xenfb_send_key(xenfb, down, keycode_table[scancode]) < 0) - fprintf(stderr, "Key %d %s lost (%s)\n", - scancode, "down", strerror(errno)); - - if (!down) - xenfb_send_key(xenfb, 0, keycode_table[0x2a]); -} - -static void press_key_shift_up(struct xenfb* xenfb, int down, int scancode) -{ - if (down) { - if (modifiers_state[0x2a]) - xenfb_send_key(xenfb, 0, keycode_table[0x2a]); - if (modifiers_state[0x36]) - xenfb_send_key(xenfb, 0, keycode_table[0x36]); - } - - if (xenfb_send_key(xenfb, down, keycode_table[scancode]) < 0) - fprintf(stderr, "Key %d %s lost (%s)\n", - scancode, "down", strerror(errno)); - - if (!down) { - if (modifiers_state[0x2a]) - xenfb_send_key(xenfb, 1, keycode_table[0x2a]); - if (modifiers_state[0x36]) - xenfb_send_key(xenfb, 1, keycode_table[0x36]); - } -} - -static void on_kbd_event(rfbBool down, rfbKeySym keycode, rfbClientPtr cl) -{ - /* - * We need to map to the key''s Linux input layer keycode. - * Unfortunately, we don''t get the key here, only the - * rfbKeySym, which is what the key is mapped to. Mapping - * back to the key is impossible in general, even when you - * know the keymap. For instance, the standard German keymap - * maps both KEY_COMMA and KEY_102ND to XK_less. We simply - * assume standard US layout. This sucks. - */ - rfbScreenInfoPtr server = cl->screen; - struct xenfb *xenfb = server->screenData; - int scancode; - int shift = 0; - int shift_keys = 0; - - if (keycode >= ''A'' && keycode <= ''Z'') { - keycode += ''a'' - ''A''; - shift = 1; - } - else { - shift = keysymIsShift(kbd_layout, keycode); - } - shift_keys = modifiers_state[0x2a] | modifiers_state[0x36]; - - scancode = keysym2scancode(kbd_layout, keycode); - if (scancode == 0) - return; - - switch(scancode) { - case 0x2a: /* Left Shift */ - case 0x36: /* Right Shift */ - case 0x1d: /* Left CTRL */ - case 0x9d: /* Right CTRL */ - case 0x38: /* Left ALT */ - case 0xb8: /* Right ALT */ - if (down) - modifiers_state[scancode] = 1; - else - modifiers_state[scancode] = 0; - xenfb_send_key(xenfb, down, keycode_table[scancode]); - return; - case 0x45: /* NumLock */ - if (!down) - modifiers_state[scancode] ^= 1; - xenfb_send_key(xenfb, down, keycode_table[scancode]); - return; - } - - if (keycodeIsKeypad(kbd_layout, scancode)) { - /* If the numlock state needs to change then simulate an additional - keypress before sending this one. This will happen if the user - toggles numlock away from the VNC window. - */ - if (keysymIsNumlock(kbd_layout, keycode)) { - if (!modifiers_state[0x45]) { - modifiers_state[0x45] = 1; - xenfb_send_key(xenfb, 1, keycode_table[0x45]); - xenfb_send_key(xenfb, 0, keycode_table[0x45]); - } - } else { - if (modifiers_state[0x45]) { - modifiers_state[0x45] = 0; - xenfb_send_key(xenfb, 1, keycode_table[0x45]); - xenfb_send_key(xenfb, 0, keycode_table[0x45]); - } - } - } - - /* If the shift state needs to change then simulate an additional - keypress before sending this one. - */ - if (shift && !shift_keys) { - press_key_shift_down(xenfb, down, scancode); - return; - } - else if (!shift && shift_keys) { - press_key_shift_up(xenfb, down, scancode); - return; - } - - if (xenfb_send_key(xenfb, down, keycode_table[scancode]) < 0) - fprintf(stderr, "Key %d %s lost (%s)\n", - scancode, down ? "down" : "up", - strerror(errno)); -} - -static void on_ptr_event(int buttonMask, int x, int y, rfbClientPtr cl) -{ - /* initial pointer state: at (0,0), buttons up */ - static int last_x, last_y, last_button; - rfbScreenInfoPtr server = cl->screen; - struct xenfb *xenfb = server->screenData; - int i, last_down, down, ret; - - for (i = 0; i < 8; i++) { - last_down = last_button & (1 << i); - down = buttonMask & (1 << i); - if (down == last_down) - continue; - if (i >= sizeof(btnmap) / sizeof(*btnmap)) - break; - if (btnmap[i] == 0) - break; - if (xenfb_send_key(xenfb, down != 0, btnmap[i]) < 0) - fprintf(stderr, "Button %d %s lost (%s)\n", - i, down ? "down" : "up", strerror(errno)); - } - - if (x != last_x || y != last_y) { - if (xenfb->abs_pointer_wanted) - ret = xenfb_send_position(xenfb, x, y); - else - ret = xenfb_send_motion(xenfb, x - last_x, y - last_y); - if (ret < 0) - fprintf(stderr, "Pointer to %d,%d lost (%s)\n", - x, y, strerror(errno)); - } - - last_button = buttonMask; - last_x = x; - last_y = y; -} - -static void xenstore_write_vncport(struct xs_handle *xsh, int port, int domid) -{ - char *buf, *path; - char portstr[10]; - - path = xs_get_domain_path(xsh, domid); - if (path == NULL) { - fprintf(stderr, "Can''t get domain path (%s)\n", - strerror(errno)); - goto out; - } - - if (asprintf(&buf, "%s/console/vnc-port", path) == -1) { - fprintf(stderr, "Can''t make vncport path\n"); - goto out; - } - - if (snprintf(portstr, sizeof(portstr), "%d", port) == -1) { - fprintf(stderr, "Can''t make vncport value\n"); - goto out; - } - - if (!xs_write(xsh, XBT_NULL, buf, portstr, strlen(portstr))) - fprintf(stderr, "Can''t set vncport (%s)\n", - strerror(errno)); - - out: - free(buf); -} - - -static int xenstore_read_vncpasswd(struct xs_handle *xsh, int domid, char *pwbuf, int pwbuflen) -{ - char buf[256], *path, *uuid = NULL, *passwd = NULL; - unsigned int len, rc = 0; - - if (xsh == NULL) { - return -1; - } - - path = xs_get_domain_path(xsh, domid); - if (path == NULL) { - fprintf(stderr, "xs_get_domain_path() error\n"); - return -1; - } - - snprintf(buf, 256, "%s/vm", path); - uuid = xs_read(xsh, XBT_NULL, buf, &len); - if (uuid == NULL) { - fprintf(stderr, "xs_read(): uuid get error\n"); - free(path); - return -1; - } - - snprintf(buf, 256, "%s/vncpasswd", uuid); - passwd = xs_read(xsh, XBT_NULL, buf, &len); - if (passwd == NULL) { - free(uuid); - free(path); - return rc; - } - - strncpy(pwbuf, passwd, pwbuflen-1); - pwbuf[pwbuflen-1] = ''\0''; - - fprintf(stderr, "Got a VNC password read from XenStore\n"); - - passwd[0] = ''\0''; - snprintf(buf, 256, "%s/vncpasswd", uuid); - if (xs_write(xsh, XBT_NULL, buf, passwd, len) == 0) { - fprintf(stderr, "xs_write() vncpasswd failed\n"); - rc = -1; - } - - free(passwd); - free(uuid); - free(path); - - return rc; -} - -static void vnc_update(struct xenfb *xenfb, int x, int y, int w, int h) -{ - rfbScreenInfoPtr server = xenfb->user_data; - rfbMarkRectAsModified(server, x, y, x + w, y + h); -} - -static struct option options[] = { - { "domid", 1, NULL, ''d'' }, - { "vncport", 1, NULL, ''p'' }, - { "title", 1, NULL, ''t'' }, - { "unused", 0, NULL, ''u'' }, - { "listen", 1, NULL, ''l'' }, - { "keymap", 1, NULL, ''k'' }, - { NULL } -}; - -int main(int argc, char **argv) -{ - rfbScreenInfoPtr server; - char *fake_argv[7] = { "vncfb", "-rfbport", "5901", - "-desktop", "xen-vncfb", - "-listen", "127.0.0.1" }; - int fake_argc = sizeof(fake_argv) / sizeof(fake_argv[0]); - int domid = -1, port = -1; - char *title = NULL; - char *listen = NULL; - char *keymap = NULL; - bool unused = false; - int opt; - struct xenfb *xenfb; - fd_set readfds; - int nfds; - char portstr[10]; - char *endp; - int r; - struct xs_handle *xsh; - char vncpasswd[1024]; - int i; - - vncpasswd[0] = ''\0''; - - while ((opt = getopt_long(argc, argv, "d:p:t:uk:", options, - NULL)) != -1) { - switch (opt) { - case ''d'': - errno = 0; - domid = strtol(optarg, &endp, 10); - if (endp == optarg || *endp || errno) { - fprintf(stderr, "Invalid domain id specified\n"); - exit(1); - } - break; - case ''p'': - errno = 0; - port = strtol(optarg, &endp, 10); - if (endp == optarg || *endp || errno) { - fprintf(stderr, "Invalid port specified\n"); - exit(1); - } - break; - case ''t'': - title = strdup(optarg); - break; - case ''u'': - unused = true; - break; - case ''l'': - listen = strdup(optarg); - break; - case ''k'': - keymap = strdup(optarg); - break; - case ''?'': - exit(1); - } - } - if (optind != argc) { - fprintf(stderr, "Invalid options!\n"); - exit(1); - } - if (domid <= 0) { - fprintf(stderr, "Domain ID must be specified!\n"); - exit(1); - } - - if (port <= 0) - port = 5900 + domid; - if (snprintf(portstr, sizeof(portstr), "%d", port) == -1) { - fprintf(stderr, "Invalid port specified\n"); - exit(1); - } - - if (keymap == NULL){ - keymap = "en-us"; - } - - kbd_layout = init_keyboard_layout(keymap); - if( !kbd_layout ){ - fprintf(stderr, "Invalid keyboard_layout\n"); - exit(1); - } - - for (i = 0; i < 128; i++) { - keycode_table[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]]; - keycode_table[i | 0x80] = - atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80]; - } - - for (i = 0; i < 256; i++ ) { - modifiers_state[i] = 0; - } - - fake_argv[2] = portstr; - - if (title != NULL) - fake_argv[4] = title; - - if (listen != NULL) - fake_argv[6] = listen; - - signal(SIGPIPE, SIG_IGN); - - xenfb = xenfb_new(); - if (xenfb == NULL) { - fprintf(stderr, "Could not create framebuffer (%s)\n", - strerror(errno)); - exit(1); - } - - if (xenfb_attach_dom(xenfb, domid) < 0) { - fprintf(stderr, "Could not connect to domain (%s)\n", - strerror(errno)); - exit(1); - } - - xsh = xs_daemon_open(); - if (xsh == NULL) { - fprintf(stderr, "cannot open connection to xenstore\n"); - exit(1); - } - - - if (xenstore_read_vncpasswd(xsh, domid, vncpasswd, - sizeof(vncpasswd)/sizeof(char)) < 0) { - fprintf(stderr, "cannot read VNC password from xenstore\n"); - exit(1); - } - - - server = rfbGetScreen(&fake_argc, fake_argv, - xenfb->width, xenfb->height, - 8, 3, xenfb->depth / 8); - if (server == NULL) { - fprintf(stderr, "Could not create VNC server\n"); - exit(1); - } - - xenfb->user_data = server; - xenfb->update = vnc_update; - - if (unused) - server->autoPort = true; - - if (vncpasswd[0]) { - char **passwds = malloc(sizeof(char**)*2); - if (!passwds) { - fprintf(stderr, "cannot allocate memory (%s)\n", - strerror(errno)); - exit(1); - } - fprintf(stderr, "Registered password\n"); - passwds[0] = vncpasswd; - passwds[1] = NULL; - - server->authPasswdData = passwds; - server->passwordCheck = rfbCheckPasswordByList; - } else { - fprintf(stderr, "Running with no password\n"); - } - server->serverFormat.redShift = 16; - server->serverFormat.greenShift = 8; - server->serverFormat.blueShift = 0; - server->kbdAddEvent = on_kbd_event; - server->ptrAddEvent = on_ptr_event; - server->frameBuffer = xenfb->pixels; - server->screenData = xenfb; - server->cursor = NULL; - rfbInitServer(server); - - rfbRunEventLoop(server, -1, true); - - xenstore_write_vncport(xsh, server->port, domid); - - for (;;) { - FD_ZERO(&readfds); - nfds = xenfb_select_fds(xenfb, &readfds); - - if (select(nfds, &readfds, NULL, NULL, NULL) < 0) { - if (errno == EINTR) - continue; - fprintf(stderr, - "Can''t select() on event channel (%s)\n", - strerror(errno)); - break; - } - - r = xenfb_poll(xenfb, &readfds); - if (r == -2) - xenfb_teardown(xenfb); - if (r < 0) - break; - } - - rfbScreenCleanup(server); - xenfb_delete(xenfb); - - return 0; -} diff -r 450e0143acaf tools/xenfb/xenfb.c --- a/tools/xenfb/xenfb.c Tue Aug 14 14:31:01 2007 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,825 +0,0 @@ -#include <stdarg.h> -#include <stdlib.h> -#include <sys/types.h> -#include <fcntl.h> -#include <unistd.h> -#include <xenctrl.h> -#include <xen/io/xenbus.h> -#include <xen/io/fbif.h> -#include <xen/io/kbdif.h> -#include <xen/io/protocols.h> -#include <sys/select.h> -#include <stdbool.h> -#include <xen/event_channel.h> -#include <sys/mman.h> -#include <errno.h> -#include <stdio.h> -#include <string.h> -#include <time.h> -#include <xs.h> - -#include "xenfb.h" - -// FIXME defend against malicious frontend? - -struct xenfb_device { - const char *devicetype; - char nodename[64]; /* backend xenstore dir */ - char otherend[64]; /* frontend xenstore dir */ - int otherend_id; /* frontend domid */ - enum xenbus_state state; /* backend state */ - void *page; /* shared page */ - evtchn_port_t port; - struct xenfb_private *xenfb; -}; - -struct xenfb_private { - struct xenfb pub; - int evt_xch; /* event channel driver handle */ - int xc; /* hypervisor interface handle */ - struct xs_handle *xsh; /* xs daemon handle */ - struct xenfb_device fb, kbd; - size_t fb_len; /* size of framebuffer */ - char protocol[64]; /* frontend protocol */ -}; - -static void xenfb_detach_dom(struct xenfb_private *); - -static char *xenfb_path_in_dom(struct xs_handle *xsh, - char *buf, size_t size, - unsigned domid, const char *fmt, ...) -{ - va_list ap; - char *domp = xs_get_domain_path(xsh, domid); - int n; - - if (domp == NULL) - return NULL; - - n = snprintf(buf, size, "%s/", domp); - free(domp); - if (n >= size) - return NULL; - - va_start(ap, fmt); - n += vsnprintf(buf + n, size - n, fmt, ap); - va_end(ap); - if (n >= size) - return NULL; - - return buf; -} - -static int xenfb_xs_scanf1(struct xs_handle *xsh, - const char *dir, const char *node, - const char *fmt, void *dest) -{ - char buf[1024]; - char *p; - int ret; - - if (snprintf(buf, sizeof(buf), "%s/%s", dir, node) >= sizeof(buf)) { - errno = ENOENT; - return -1; - } - p = xs_read(xsh, XBT_NULL, buf, NULL); - if (!p) { - errno = ENOENT; - return -1; - } - ret = sscanf(p, fmt, dest); - free(p); - if (ret != 1) { - errno = EDOM; - return -1; - } - return ret; -} - -static int xenfb_xs_printf(struct xs_handle *xsh, - const char *dir, const char *node, char *fmt, ...) -{ - va_list ap; - char key[1024]; - char val[1024]; - int n; - - if (snprintf(key, sizeof(key), "%s/%s", dir, node) >= sizeof(key)) { - errno = ENOENT; - return -1; - } - - va_start(ap, fmt); - n = vsnprintf(val, sizeof(val), fmt, ap); - va_end(ap); - if (n >= sizeof(val)) { - errno = ENOSPC; /* close enough */ - return -1; - } - - if (!xs_write(xsh, XBT_NULL, key, val, n)) - return -1; - return 0; -} - -static void xenfb_device_init(struct xenfb_device *dev, - const char *type, - struct xenfb_private *xenfb) -{ - dev->devicetype = type; - dev->otherend_id = -1; - dev->port = -1; - dev->xenfb = xenfb; -} - -int xenfb_device_set_domain(struct xenfb_device *dev, int domid) -{ - struct xenfb_private *xenfb = dev->xenfb; - - dev->otherend_id = domid; - - if (!xenfb_path_in_dom(xenfb->xsh, - dev->otherend, sizeof(dev->otherend), - domid, "device/%s/0", dev->devicetype)) { - errno = ENOENT; - return -1; - } - if (!xenfb_path_in_dom(xenfb->xsh, - dev->nodename, sizeof(dev->nodename), - 0, "backend/%s/%d/0", dev->devicetype, domid)) { - errno = ENOENT; - return -1; - } - - return 0; -} - -struct xenfb *xenfb_new(void) -{ - struct xenfb_private *xenfb = malloc(sizeof(*xenfb)); - int serrno; - - if (xenfb == NULL) - return NULL; - - memset(xenfb, 0, sizeof(*xenfb)); - xenfb->evt_xch = xenfb->xc = -1; - xenfb_device_init(&xenfb->fb, "vfb", xenfb); - xenfb_device_init(&xenfb->kbd, "vkbd", xenfb); - - xenfb->evt_xch = xc_evtchn_open(); - if (xenfb->evt_xch == -1) - goto fail; - - xenfb->xc = xc_interface_open(); - if (xenfb->xc == -1) - goto fail; - - xenfb->xsh = xs_daemon_open(); - if (!xenfb->xsh) - goto fail; - - return &xenfb->pub; - - fail: - serrno = errno; - xenfb_delete(&xenfb->pub); - errno = serrno; - return NULL; -} - -/* Remove the backend area in xenbus since the framebuffer really is - going away. */ -void xenfb_teardown(struct xenfb *xenfb_pub) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - - xs_rm(xenfb->xsh, XBT_NULL, xenfb->fb.nodename); - xs_rm(xenfb->xsh, XBT_NULL, xenfb->kbd.nodename); -} - - -void xenfb_delete(struct xenfb *xenfb_pub) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - - xenfb_detach_dom(xenfb); - if (xenfb->xc >= 0) - xc_interface_close(xenfb->xc); - if (xenfb->evt_xch >= 0) - xc_evtchn_close(xenfb->evt_xch); - if (xenfb->xsh) - xs_daemon_close(xenfb->xsh); - free(xenfb); -} - -static enum xenbus_state xenfb_read_state(struct xs_handle *xsh, - const char *dir) -{ - int ret, state; - - ret = xenfb_xs_scanf1(xsh, dir, "state", "%d", &state); - if (ret < 0) - return XenbusStateUnknown; - - if ((unsigned)state > XenbusStateClosed) - state = XenbusStateUnknown; - return state; -} - -static int xenfb_switch_state(struct xenfb_device *dev, - enum xenbus_state state) -{ - struct xs_handle *xsh = dev->xenfb->xsh; - - if (xenfb_xs_printf(xsh, dev->nodename, "state", "%d", state) < 0) - return -1; - dev->state = state; - return 0; -} - -static int xenfb_wait_for_state(struct xs_handle *xsh, const char *dir, - unsigned awaited) -{ - unsigned state, dummy; - char **vec; - - awaited |= 1 << XenbusStateUnknown; - - for (;;) { - state = xenfb_read_state(xsh, dir); - if ((1 << state) & awaited) - return state; - - vec = xs_read_watch(xsh, &dummy); - if (!vec) - return -1; - free(vec); - } -} - -static int xenfb_wait_for_backend_creation(struct xenfb_device *dev) -{ - struct xs_handle *xsh = dev->xenfb->xsh; - int state; - - if (!xs_watch(xsh, dev->nodename, "")) - return -1; - state = xenfb_wait_for_state(xsh, dev->nodename, - (1 << XenbusStateInitialising) - | (1 << XenbusStateClosed) -#if 1 /* TODO fudging state to permit restarting; to be removed */ - | (1 << XenbusStateInitWait) - | (1 << XenbusStateConnected) - | (1 << XenbusStateClosing) -#endif - ); - xs_unwatch(xsh, dev->nodename, ""); - - switch (state) { -#if 1 - case XenbusStateInitWait: - case XenbusStateConnected: - printf("Fudging state to %d\n", XenbusStateInitialising); /* FIXME */ -#endif - case XenbusStateInitialising: - case XenbusStateClosing: - case XenbusStateClosed: - break; - default: - return -1; - } - - return 0; -} - -static int xenfb_hotplug(struct xenfb_device *dev) -{ - if (xenfb_xs_printf(dev->xenfb->xsh, dev->nodename, - "hotplug-status", "connected")) - return -1; - return 0; -} - -static int xenfb_wait_for_frontend_initialised(struct xenfb_device *dev) -{ - switch (xenfb_wait_for_state(dev->xenfb->xsh, dev->otherend, -#if 1 /* TODO fudging state to permit restarting; to be removed */ - (1 << XenbusStateInitialised) - | (1 << XenbusStateConnected) -#else - 1 << XenbusStateInitialised, -#endif - )) { -#if 1 - case XenbusStateConnected: - printf("Fudging state to %d\n", XenbusStateInitialised); /* FIXME */ -#endif - case XenbusStateInitialised: - break; - default: - return -1; - } - - return 0; -} - -static void xenfb_copy_mfns(int mode, int count, unsigned long *dst, void *src) -{ - uint32_t *src32 = src; - uint64_t *src64 = src; - int i; - - for (i = 0; i < count; i++) - dst[i] = (mode == 32) ? src32[i] : src64[i]; -} - -static int xenfb_map_fb(struct xenfb_private *xenfb, int domid) -{ - struct xenfb_page *page = xenfb->fb.page; - int n_fbmfns; - int n_fbdirs; - unsigned long *pgmfns = NULL; - unsigned long *fbmfns = NULL; - void *map, *pd; - int mode, ret = -1; - - /* default to native */ - pd = page->pd; - mode = sizeof(unsigned long) * 8; - - if (0 == strlen(xenfb->protocol)) { - /* - * Undefined protocol, some guesswork needed. - * - * Old frontends which don''t set the protocol use - * one page directory only, thus pd[1] must be zero. - * pd[1] of the 32bit struct layout and the lower - * 32 bits of pd[0] of the 64bit struct layout have - * the same location, so we can check that ... - */ - uint32_t *ptr32 = NULL; - uint32_t *ptr64 = NULL; -#if defined(__i386__) - ptr32 = (void*)page->pd; - ptr64 = ((void*)page->pd) + 4; -#elif defined(__x86_64__) - ptr32 = ((void*)page->pd) - 4; - ptr64 = (void*)page->pd; -#endif - if (ptr32) { - if (0 == ptr32[1]) { - mode = 32; - pd = ptr32; - } else { - mode = 64; - pd = ptr64; - } - } -#if defined(__x86_64__) - } else if (0 == strcmp(xenfb->protocol, XEN_IO_PROTO_ABI_X86_32)) { - /* 64bit dom0, 32bit domU */ - mode = 32; - pd = ((void*)page->pd) - 4; -#elif defined(__i386__) - } else if (0 == strcmp(xenfb->protocol, XEN_IO_PROTO_ABI_X86_64)) { - /* 32bit dom0, 64bit domU */ - mode = 64; - pd = ((void*)page->pd) + 4; -#endif - } - - n_fbmfns = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE; - n_fbdirs = n_fbmfns * mode / 8; - n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE; - - pgmfns = malloc(sizeof(unsigned long) * n_fbdirs); - fbmfns = malloc(sizeof(unsigned long) * n_fbmfns); - if (!pgmfns || !fbmfns) - goto out; - - /* - * Bug alert: xc_map_foreign_batch() can fail partly and - * return a non-null value. This is a design flaw. When it - * happens, we happily continue here, and later crash on - * access. - */ - xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd); - map = xc_map_foreign_batch(xenfb->xc, domid, - PROT_READ, pgmfns, n_fbdirs); - if (map == NULL) - goto out; - xenfb_copy_mfns(mode, n_fbmfns, fbmfns, map); - munmap(map, n_fbdirs * XC_PAGE_SIZE); - - xenfb->pub.pixels = xc_map_foreign_batch(xenfb->xc, domid, - PROT_READ | PROT_WRITE, fbmfns, n_fbmfns); - if (xenfb->pub.pixels == NULL) - goto out; - - ret = 0; /* all is fine */ - - out: - if (pgmfns) - free(pgmfns); - if (fbmfns) - free(fbmfns); - return ret; -} - -static int xenfb_bind(struct xenfb_device *dev) -{ - struct xenfb_private *xenfb = dev->xenfb; - unsigned long mfn; - evtchn_port_t evtchn; - - if (xenfb_xs_scanf1(xenfb->xsh, dev->otherend, "page-ref", "%lu", - &mfn) < 0) - return -1; - if (xenfb_xs_scanf1(xenfb->xsh, dev->otherend, "event-channel", "%u", - &evtchn) < 0) - return -1; - - dev->port = xc_evtchn_bind_interdomain(xenfb->evt_xch, - dev->otherend_id, evtchn); - if (dev->port == -1) - return -1; - - dev->page = xc_map_foreign_range(xenfb->xc, dev->otherend_id, - XC_PAGE_SIZE, PROT_READ | PROT_WRITE, mfn); - if (dev->page == NULL) - return -1; - - return 0; -} - -static void xenfb_unbind(struct xenfb_device *dev) -{ - if (dev->page) { - munmap(dev->page, XC_PAGE_SIZE); - dev->page = NULL; - } - if (dev->port >= 0) { - xc_evtchn_unbind(dev->xenfb->evt_xch, dev->port); - dev->port = -1; - } -} - -static int xenfb_wait_for_frontend_connected(struct xenfb_device *dev) -{ - switch (xenfb_wait_for_state(dev->xenfb->xsh, dev->otherend, - 1 << XenbusStateConnected)) { - case XenbusStateConnected: - break; - default: - return -1; - } - - return 0; -} - -static void xenfb_dev_fatal(struct xenfb_device *dev, int err, - const char *fmt, ...) -{ - struct xs_handle *xsh = dev->xenfb->xsh; - va_list ap; - char errdir[80]; - char buf[1024]; - int n; - - fprintf(stderr, "%s ", dev->nodename); /* somewhat crude */ - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - if (err) - fprintf(stderr, " (%s)", strerror(err)); - putc(''\n'', stderr); - - if (!xenfb_path_in_dom(xsh, errdir, sizeof(errdir), 0, - "error/%s", dev->nodename)) - goto out; /* FIXME complain */ - - va_start(ap, fmt); - n = snprintf(buf, sizeof(buf), "%d ", err); - snprintf(buf + n, sizeof(buf) - n, fmt, ap); - va_end(ap); - - if (xenfb_xs_printf(xsh, buf, "error", "%s", buf) < 0) - goto out; /* FIXME complain */ - - out: - xenfb_switch_state(dev, XenbusStateClosing); -} - -int xenfb_attach_dom(struct xenfb *xenfb_pub, int domid) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - struct xs_handle *xsh = xenfb->xsh; - int val, serrno; - struct xenfb_page *fb_page; - - xenfb_detach_dom(xenfb); - - xenfb_device_set_domain(&xenfb->fb, domid); - xenfb_device_set_domain(&xenfb->kbd, domid); - - if (xenfb_wait_for_backend_creation(&xenfb->fb) < 0) - goto error; - if (xenfb_wait_for_backend_creation(&xenfb->kbd) < 0) - goto error; - - if (xenfb_xs_printf(xsh, xenfb->kbd.nodename, "feature-abs-pointer", "1")) - goto error; - if (xenfb_switch_state(&xenfb->fb, XenbusStateInitWait)) - goto error; - if (xenfb_switch_state(&xenfb->kbd, XenbusStateInitWait)) - goto error; - - if (xenfb_hotplug(&xenfb->fb) < 0) - goto error; - if (xenfb_hotplug(&xenfb->kbd) < 0) - goto error; - - if (!xs_watch(xsh, xenfb->fb.otherend, "")) - goto error; - if (!xs_watch(xsh, xenfb->kbd.otherend, "")) - goto error; - - if (xenfb_wait_for_frontend_initialised(&xenfb->fb) < 0) - goto error; - if (xenfb_wait_for_frontend_initialised(&xenfb->kbd) < 0) - goto error; - - if (xenfb_bind(&xenfb->fb) < 0) - goto error; - if (xenfb_bind(&xenfb->kbd) < 0) - goto error; - - if (xenfb_xs_scanf1(xsh, xenfb->fb.otherend, "feature-update", - "%d", &val) < 0) - val = 0; - if (!val) { - errno = ENOTSUP; - goto error; - } - if (xenfb_xs_scanf1(xsh, xenfb->fb.otherend, "protocol", "%63s", - xenfb->protocol) < 0) - xenfb->protocol[0] = ''\0''; - xenfb_xs_printf(xsh, xenfb->fb.nodename, "request-update", "1"); - - /* TODO check for permitted ranges */ - fb_page = xenfb->fb.page; - xenfb->pub.depth = fb_page->depth; - xenfb->pub.width = fb_page->width; - xenfb->pub.height = fb_page->height; - /* TODO check for consistency with the above */ - xenfb->fb_len = fb_page->mem_length; - xenfb->pub.row_stride = fb_page->line_length; - - if (xenfb_map_fb(xenfb, domid) < 0) - goto error; - - if (xenfb_switch_state(&xenfb->fb, XenbusStateConnected)) - goto error; - if (xenfb_switch_state(&xenfb->kbd, XenbusStateConnected)) - goto error; - - if (xenfb_wait_for_frontend_connected(&xenfb->kbd) < 0) - goto error; - if (xenfb_xs_scanf1(xsh, xenfb->kbd.otherend, "request-abs-pointer", - "%d", &val) < 0) - val = 0; - xenfb->pub.abs_pointer_wanted = val; - - return 0; - - error: - serrno = errno; - xenfb_detach_dom(xenfb); - xenfb_dev_fatal(&xenfb->fb, serrno, "on fire"); - xenfb_dev_fatal(&xenfb->kbd, serrno, "on fire"); - errno = serrno; - return -1; -} - -static void xenfb_detach_dom(struct xenfb_private *xenfb) -{ - xenfb_unbind(&xenfb->fb); - xenfb_unbind(&xenfb->kbd); - if (xenfb->pub.pixels) { - munmap(xenfb->pub.pixels, xenfb->fb_len); - xenfb->pub.pixels = NULL; - } -} - -static void xenfb_on_fb_event(struct xenfb_private *xenfb) -{ - uint32_t prod, cons; - struct xenfb_page *page = xenfb->fb.page; - - prod = page->out_prod; - if (prod == page->out_cons) - return; - rmb(); /* ensure we see ring contents up to prod */ - for (cons = page->out_cons; cons != prod; cons++) { - union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons); - - switch (event->type) { - case XENFB_TYPE_UPDATE: - if (xenfb->pub.update) - xenfb->pub.update(&xenfb->pub, - event->update.x, event->update.y, - event->update.width, event->update.height); - break; - } - } - mb(); /* ensure we''re done with ring contents */ - page->out_cons = cons; - xc_evtchn_notify(xenfb->evt_xch, xenfb->fb.port); -} - -static void xenfb_on_kbd_event(struct xenfb_private *xenfb) -{ - struct xenkbd_page *page = xenfb->kbd.page; - - /* We don''t understand any keyboard events, so just ignore them. */ - if (page->out_prod == page->out_cons) - return; - page->out_cons = page->out_prod; - xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port); -} - -static int xenfb_on_state_change(struct xenfb_device *dev) -{ - enum xenbus_state state; - - state = xenfb_read_state(dev->xenfb->xsh, dev->otherend); - - switch (state) { - case XenbusStateUnknown: - /* There was an error reading the frontend state. The - domain has probably gone away; in any case, there''s - not much point in us continuing. */ - return -1; - case XenbusStateInitialising: - case XenbusStateInitWait: - case XenbusStateInitialised: - case XenbusStateConnected: - break; - case XenbusStateClosing: - xenfb_unbind(dev); - xenfb_switch_state(dev, state); - break; - case XenbusStateClosed: - xenfb_switch_state(dev, state); - } - return 0; -} - -int xenfb_dispatch_channel(struct xenfb *xenfb_pub) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - evtchn_port_t port; - port = xc_evtchn_pending(xenfb->evt_xch); - if (port == -1) - return -1; - - if (port == xenfb->fb.port) - xenfb_on_fb_event(xenfb); - else if (port == xenfb->kbd.port) - xenfb_on_kbd_event(xenfb); - - if (xc_evtchn_unmask(xenfb->evt_xch, port) == -1) - return -1; - - return 0; -} - -int xenfb_dispatch_store(struct xenfb *xenfb_pub) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - unsigned dummy; - char **vec; - int r; - - vec = xs_read_watch(xenfb->xsh, &dummy); - free(vec); - r = xenfb_on_state_change(&xenfb->fb); - if (r == 0) - r = xenfb_on_state_change(&xenfb->kbd); - if (r == -1) - return -2; - - return 0; -} - - -/* Returns 0 normally, -1 on error, or -2 if the domain went away. */ -int xenfb_poll(struct xenfb *xenfb_pub, fd_set *readfds) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - int ret; - - if (FD_ISSET(xc_evtchn_fd(xenfb->evt_xch), readfds)) { - if ((ret = xenfb_dispatch_channel(xenfb_pub)) < 0) - return ret; - } - - if (FD_ISSET(xs_fileno(xenfb->xsh), readfds)) { - if ((ret = xenfb_dispatch_store(xenfb_pub)) < 0) - return ret; - } - - return 0; -} - -int xenfb_select_fds(struct xenfb *xenfb_pub, fd_set *readfds) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - int fd1 = xc_evtchn_fd(xenfb->evt_xch); - int fd2 = xs_fileno(xenfb->xsh); - - FD_SET(fd1, readfds); - FD_SET(fd2, readfds); - return fd1 > fd2 ? fd1 + 1 : fd2 + 1; -} - -int xenfb_get_store_fd(struct xenfb *xenfb_pub) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - return xs_fileno(xenfb->xsh); -} - -int xenfb_get_channel_fd(struct xenfb *xenfb_pub) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - return xc_evtchn_fd(xenfb->evt_xch); -} - -static int xenfb_kbd_event(struct xenfb_private *xenfb, - union xenkbd_in_event *event) -{ - uint32_t prod; - struct xenkbd_page *page = xenfb->kbd.page; - - if (xenfb->kbd.state != XenbusStateConnected) - return 0; - - prod = page->in_prod; - if (prod - page->in_cons == XENKBD_IN_RING_LEN) { - errno = EAGAIN; - return -1; - } - - mb(); /* ensure ring space available */ - XENKBD_IN_RING_REF(page, prod) = *event; - wmb(); /* ensure ring contents visible */ - page->in_prod = prod + 1; - return xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port); -} - -int xenfb_send_key(struct xenfb *xenfb_pub, bool down, int keycode) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - union xenkbd_in_event event; - - memset(&event, 0, XENKBD_IN_EVENT_SIZE); - event.type = XENKBD_TYPE_KEY; - event.key.pressed = down ? 1 : 0; - event.key.keycode = keycode; - - return xenfb_kbd_event(xenfb, &event); -} - -int xenfb_send_motion(struct xenfb *xenfb_pub, int rel_x, int rel_y) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - union xenkbd_in_event event; - - memset(&event, 0, XENKBD_IN_EVENT_SIZE); - event.type = XENKBD_TYPE_MOTION; - event.motion.rel_x = rel_x; - event.motion.rel_y = rel_y; - - return xenfb_kbd_event(xenfb, &event); -} - -int xenfb_send_position(struct xenfb *xenfb_pub, int abs_x, int abs_y) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - union xenkbd_in_event event; - - memset(&event, 0, XENKBD_IN_EVENT_SIZE); - event.type = XENKBD_TYPE_POS; - event.pos.abs_x = abs_x; - event.pos.abs_y = abs_y; - - return xenfb_kbd_event(xenfb, &event); -} -/* - * Local variables: - * c-indent-level: 8 - * c-basic-offset: 8 - * tab-width: 8 - * End: - */ diff -r 450e0143acaf tools/xenfb/xenfb.h --- a/tools/xenfb/xenfb.h Tue Aug 14 14:31:01 2007 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -#ifndef _XENFB_H_ -#define _XENFB_H_ - -#include <stdbool.h> -#include <sys/types.h> - -struct xenfb -{ - void *pixels; - - int row_stride; - int depth; - int width; - int height; - int abs_pointer_wanted; - - void *user_data; - - void (*update)(struct xenfb *xenfb, int x, int y, int width, int height); -}; - -struct xenfb *xenfb_new(void); -void xenfb_delete(struct xenfb *xenfb); -void xenfb_teardown(struct xenfb *xenfb); - -int xenfb_attach_dom(struct xenfb *xenfb, int domid); - -int xenfb_dispatch_store(struct xenfb *xenfb_pub); -int xenfb_dispatch_channel(struct xenfb *xenfb_pub); -int xenfb_select_fds(struct xenfb *xenfb, fd_set *readfds); -int xenfb_poll(struct xenfb *xenfb, fd_set *readfds); -int xenfb_get_store_fd(struct xenfb *xenfb_pub); -int xenfb_get_channel_fd(struct xenfb *xenfb_pub); - -int xenfb_send_key(struct xenfb *xenfb, bool down, int keycode); -int xenfb_send_motion(struct xenfb *xenfb, int rel_x, int rel_y); -int xenfb_send_position(struct xenfb *xenfb, int abs_x, int abs_y); - -#endif -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=| _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel P. Berrange
2007-Aug-22 22:30 UTC
Re: [Xen-devel] PATCH: 4/10: Refactor xenfb event handlers
This patch is a simple code re-factoring to move the event loop integration directly into the xenfb.c file. It is to facilitate the patches which follow. xen_machine_pv.c | 29 ------ xenfb.c | 249 +++++++++++++++++++++++-------------------------------- xenfb.h | 7 - 3 files changed, 106 insertions(+), 179 deletions(-) Signed-off-by: Daniel P. Berrange <berrange@redhat.com> Dan. diff -r bd1bddd42929 tools/ioemu/hw/xen_machine_pv.c --- a/tools/ioemu/hw/xen_machine_pv.c Tue Aug 14 14:38:28 2007 -0400 +++ b/tools/ioemu/hw/xen_machine_pv.c Tue Aug 14 15:04:55 2007 -0400 @@ -136,21 +136,6 @@ void xen_pvfb_invalidate(void *opaque) /* Screen dump is not used in Xen, so no need to impl this ? */ void xen_pvfb_screen_dump(void *opaque, const char *name) { } -void xen_pvfb_dispatch_store(void *opaque) { - int ret; - if ((ret = xenfb_dispatch_store((struct xenfb *)opaque)) < 0) { - fprintf(stderr, "Failure while dispatching store: %d\n", ret); - exit(1); - } -} - -void xen_pvfb_dispatch_channel(void *opaque) { - int ret; - if ((ret = xenfb_dispatch_channel((struct xenfb *)opaque)) < 0) { - fprintf(stderr, "Failure while dispatching store: %d\n", ret); - exit(1); - } -} /* The Xen PV machine currently provides * - a virtual framebuffer @@ -165,7 +150,6 @@ static void xen_init_pv(uint64_t ram_siz { struct xenfb *xenfb; extern int domid; - int fd; /* Prepare PVFB state */ xenfb = xenfb_new(); @@ -197,19 +181,6 @@ static void xen_init_pv(uint64_t ram_siz xenfb->abs_pointer_wanted, "Xen PVFB Mouse"); - /* Listen for events from xenstore */ - fd = xenfb_get_store_fd(xenfb); - if (qemu_set_fd_handler2(fd, NULL, xen_pvfb_dispatch_store, NULL, xenfb) < 0) { - fprintf(stderr, "Could not register event handler (%s)\n", - strerror(errno)); - } - - /* Listen for events from the event channel */ - fd = xenfb_get_channel_fd(xenfb); - if (qemu_set_fd_handler2(fd, NULL, xen_pvfb_dispatch_channel, NULL, xenfb) < 0) { - fprintf(stderr, "Could not register event handler (%s)\n", - strerror(errno)); - } /* Setup QEMU display */ dpy_resize(ds, xenfb->width, xenfb->height); diff -r bd1bddd42929 tools/ioemu/hw/xenfb.c --- a/tools/ioemu/hw/xenfb.c Tue Aug 14 14:38:28 2007 -0400 +++ b/tools/ioemu/hw/xenfb.c Tue Aug 14 15:10:27 2007 -0400 @@ -8,7 +8,6 @@ #include <xen/io/fbif.h> #include <xen/io/kbdif.h> #include <xen/io/protocols.h> -#include <sys/select.h> #include <stdbool.h> #include <xen/event_channel.h> #include <sys/mman.h> @@ -18,6 +17,7 @@ #include <time.h> #include <xs.h> +#include "vl.h" #include "xenfb.h" // FIXME defend against malicious frontend? @@ -511,96 +511,6 @@ static void xenfb_dev_fatal(struct xenfb xenfb_switch_state(dev, XenbusStateClosing); } -int xenfb_attach_dom(struct xenfb *xenfb_pub, int domid) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - struct xs_handle *xsh = xenfb->xsh; - int val, serrno; - struct xenfb_page *fb_page; - - xenfb_detach_dom(xenfb); - - xenfb_device_set_domain(&xenfb->fb, domid); - xenfb_device_set_domain(&xenfb->kbd, domid); - - if (xenfb_wait_for_backend_creation(&xenfb->fb) < 0) - goto error; - if (xenfb_wait_for_backend_creation(&xenfb->kbd) < 0) - goto error; - - if (xenfb_xs_printf(xsh, xenfb->kbd.nodename, "feature-abs-pointer", "1")) - goto error; - if (xenfb_switch_state(&xenfb->fb, XenbusStateInitWait)) - goto error; - if (xenfb_switch_state(&xenfb->kbd, XenbusStateInitWait)) - goto error; - - if (xenfb_hotplug(&xenfb->fb) < 0) - goto error; - if (xenfb_hotplug(&xenfb->kbd) < 0) - goto error; - - if (!xs_watch(xsh, xenfb->fb.otherend, "")) - goto error; - if (!xs_watch(xsh, xenfb->kbd.otherend, "")) - goto error; - - if (xenfb_wait_for_frontend_initialised(&xenfb->fb) < 0) - goto error; - if (xenfb_wait_for_frontend_initialised(&xenfb->kbd) < 0) - goto error; - - if (xenfb_bind(&xenfb->fb) < 0) - goto error; - if (xenfb_bind(&xenfb->kbd) < 0) - goto error; - - if (xenfb_xs_scanf1(xsh, xenfb->fb.otherend, "feature-update", - "%d", &val) < 0) - val = 0; - if (!val) { - errno = ENOTSUP; - goto error; - } - if (xenfb_xs_scanf1(xsh, xenfb->fb.otherend, "protocol", "%63s", - xenfb->protocol) < 0) - xenfb->protocol[0] = ''\0''; - xenfb_xs_printf(xsh, xenfb->fb.nodename, "request-update", "1"); - - /* TODO check for permitted ranges */ - fb_page = xenfb->fb.page; - xenfb->pub.depth = fb_page->depth; - xenfb->pub.width = fb_page->width; - xenfb->pub.height = fb_page->height; - /* TODO check for consistency with the above */ - xenfb->fb_len = fb_page->mem_length; - xenfb->pub.row_stride = fb_page->line_length; - - if (xenfb_map_fb(xenfb, domid) < 0) - goto error; - - if (xenfb_switch_state(&xenfb->fb, XenbusStateConnected)) - goto error; - if (xenfb_switch_state(&xenfb->kbd, XenbusStateConnected)) - goto error; - - if (xenfb_wait_for_frontend_connected(&xenfb->kbd) < 0) - goto error; - if (xenfb_xs_scanf1(xsh, xenfb->kbd.otherend, "request-abs-pointer", - "%d", &val) < 0) - val = 0; - xenfb->pub.abs_pointer_wanted = val; - - return 0; - - error: - serrno = errno; - xenfb_detach_dom(xenfb); - xenfb_dev_fatal(&xenfb->fb, serrno, "on fire"); - xenfb_dev_fatal(&xenfb->kbd, serrno, "on fire"); - errno = serrno; - return -1; -} static void xenfb_detach_dom(struct xenfb_private *xenfb) { @@ -676,13 +586,13 @@ static int xenfb_on_state_change(struct return 0; } -int xenfb_dispatch_channel(struct xenfb *xenfb_pub) +static void xenfb_dispatch_channel(void *xenfb_pub) { struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; evtchn_port_t port; port = xc_evtchn_pending(xenfb->evt_xch); if (port == -1) - return -1; + exit(1); if (port == xenfb->fb.port) xenfb_on_fb_event(xenfb); @@ -690,12 +600,10 @@ int xenfb_dispatch_channel(struct xenfb xenfb_on_kbd_event(xenfb); if (xc_evtchn_unmask(xenfb->evt_xch, port) == -1) - return -1; - - return 0; -} - -int xenfb_dispatch_store(struct xenfb *xenfb_pub) + exit(1); +} + +static void xenfb_dispatch_store(void *xenfb_pub) { struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; unsigned dummy; @@ -708,52 +616,107 @@ int xenfb_dispatch_store(struct xenfb *x if (r == 0) r = xenfb_on_state_change(&xenfb->kbd); if (r == -1) - return -2; - - return 0; -} - - -/* Returns 0 normally, -1 on error, or -2 if the domain went away. */ -int xenfb_poll(struct xenfb *xenfb_pub, fd_set *readfds) + exit(1); +} + + +int xenfb_attach_dom(struct xenfb *xenfb_pub, int domid) { struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - int ret; - - if (FD_ISSET(xc_evtchn_fd(xenfb->evt_xch), readfds)) { - if ((ret = xenfb_dispatch_channel(xenfb_pub)) < 0) - return ret; - } - - if (FD_ISSET(xs_fileno(xenfb->xsh), readfds)) { - if ((ret = xenfb_dispatch_store(xenfb_pub)) < 0) - return ret; - } - - return 0; -} - -int xenfb_select_fds(struct xenfb *xenfb_pub, fd_set *readfds) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - int fd1 = xc_evtchn_fd(xenfb->evt_xch); - int fd2 = xs_fileno(xenfb->xsh); - - FD_SET(fd1, readfds); - FD_SET(fd2, readfds); - return fd1 > fd2 ? fd1 + 1 : fd2 + 1; -} - -int xenfb_get_store_fd(struct xenfb *xenfb_pub) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - return xs_fileno(xenfb->xsh); -} - -int xenfb_get_channel_fd(struct xenfb *xenfb_pub) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - return xc_evtchn_fd(xenfb->evt_xch); + struct xs_handle *xsh = xenfb->xsh; + int val, serrno; + struct xenfb_page *fb_page; + + xenfb_detach_dom(xenfb); + + xenfb_device_set_domain(&xenfb->fb, domid); + xenfb_device_set_domain(&xenfb->kbd, domid); + + if (xenfb_wait_for_backend_creation(&xenfb->fb) < 0) + goto error; + if (xenfb_wait_for_backend_creation(&xenfb->kbd) < 0) + goto error; + + if (xenfb_xs_printf(xsh, xenfb->kbd.nodename, "feature-abs-pointer", "1")) + goto error; + if (xenfb_switch_state(&xenfb->fb, XenbusStateInitWait)) + goto error; + if (xenfb_switch_state(&xenfb->kbd, XenbusStateInitWait)) + goto error; + + if (xenfb_hotplug(&xenfb->fb) < 0) + goto error; + if (xenfb_hotplug(&xenfb->kbd) < 0) + goto error; + + if (!xs_watch(xsh, xenfb->fb.otherend, "")) + goto error; + if (!xs_watch(xsh, xenfb->kbd.otherend, "")) + goto error; + + if (xenfb_wait_for_frontend_initialised(&xenfb->fb) < 0) + goto error; + if (xenfb_wait_for_frontend_initialised(&xenfb->kbd) < 0) + goto error; + + if (xenfb_bind(&xenfb->fb) < 0) + goto error; + if (xenfb_bind(&xenfb->kbd) < 0) + goto error; + + if (xenfb_xs_scanf1(xsh, xenfb->fb.otherend, "feature-update", + "%d", &val) < 0) + val = 0; + if (!val) { + errno = ENOTSUP; + goto error; + } + if (xenfb_xs_scanf1(xsh, xenfb->fb.otherend, "protocol", "%63s", + xenfb->protocol) < 0) + xenfb->protocol[0] = ''\0''; + xenfb_xs_printf(xsh, xenfb->fb.nodename, "request-update", "1"); + + /* TODO check for permitted ranges */ + fb_page = xenfb->fb.page; + xenfb->pub.depth = fb_page->depth; + xenfb->pub.width = fb_page->width; + xenfb->pub.height = fb_page->height; + /* TODO check for consistency with the above */ + xenfb->fb_len = fb_page->mem_length; + xenfb->pub.row_stride = fb_page->line_length; + + if (xenfb_map_fb(xenfb, domid) < 0) + goto error; + + if (xenfb_switch_state(&xenfb->fb, XenbusStateConnected)) + goto error; + if (xenfb_switch_state(&xenfb->kbd, XenbusStateConnected)) + goto error; + + if (xenfb_wait_for_frontend_connected(&xenfb->kbd) < 0) + goto error; + if (xenfb_xs_scanf1(xsh, xenfb->kbd.otherend, "request-abs-pointer", + "%d", &val) < 0) + val = 0; + xenfb->pub.abs_pointer_wanted = val; + + /* Listen for events from xenstore */ + if (qemu_set_fd_handler2(xs_fileno(xenfb->xsh), NULL, xenfb_dispatch_store, NULL, xenfb) < 0) + goto error; + + /* Listen for events from the event channel */ + if (qemu_set_fd_handler2(xc_evtchn_fd(xenfb->evt_xch), NULL, xenfb_dispatch_channel, NULL, xenfb) < 0) + goto error; + + return 0; + + error: + serrno = errno; + xenfb_detach_dom(xenfb); + xenfb_dev_fatal(&xenfb->fb, serrno, "on fire"); + xenfb_dev_fatal(&xenfb->kbd, serrno, "on fire"); + errno = serrno; + return -1; } static int xenfb_kbd_event(struct xenfb_private *xenfb, diff -r bd1bddd42929 tools/ioemu/hw/xenfb.h --- a/tools/ioemu/hw/xenfb.h Tue Aug 14 14:38:28 2007 -0400 +++ b/tools/ioemu/hw/xenfb.h Tue Aug 14 15:03:42 2007 -0400 @@ -25,13 +25,6 @@ void xenfb_teardown(struct xenfb *xenfb) int xenfb_attach_dom(struct xenfb *xenfb, int domid); -int xenfb_dispatch_store(struct xenfb *xenfb_pub); -int xenfb_dispatch_channel(struct xenfb *xenfb_pub); -int xenfb_select_fds(struct xenfb *xenfb, fd_set *readfds); -int xenfb_poll(struct xenfb *xenfb, fd_set *readfds); -int xenfb_get_store_fd(struct xenfb *xenfb_pub); -int xenfb_get_channel_fd(struct xenfb *xenfb_pub); - int xenfb_send_key(struct xenfb *xenfb, bool down, int keycode); int xenfb_send_motion(struct xenfb *xenfb, int rel_x, int rel_y); int xenfb_send_position(struct xenfb *xenfb, int abs_x, int abs_y); -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=| _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel P. Berrange
2007-Aug-22 22:31 UTC
Re: [Xen-devel] PATCH: 5/10: Refactor QEMU console integration
This patch moves a bunch of code out of the xen_machine_pv.c file and into the xenfb.c file. This is simply a re-factoring to facilitate the two patches which follow. xen_machine_pv.c | 132 ---------------------------- xenfb.c | 254 +++++++++++++++++++++++++++++++++++++++++-------------- xenfb.h | 8 - 3 files changed, 195 insertions(+), 199 deletions(-) Signed-off-by: Daniel P. Berrange <berrange@redhat.com> Dan. diff -r c2aa6c7965a3 tools/ioemu/hw/xen_machine_pv.c --- a/tools/ioemu/hw/xen_machine_pv.c Wed Aug 15 14:17:30 2007 -0400 +++ b/tools/ioemu/hw/xen_machine_pv.c Tue Aug 21 22:03:27 2007 -0400 @@ -24,117 +24,6 @@ #include "vl.h" #include "xenfb.h" -#include <linux/input.h> - -/* A convenient function for munging pixels between different depths */ -#define BLT(SRC_T,DST_T,RLS,GLS,BLS,RRS,GRS,BRS,RM,GM,BM) \ - for (line = y ; line < h ; line++) { \ - SRC_T *src = (SRC_T *)(xenfb->pixels + (line*xenfb->row_stride) + (x*xenfb->depth/8)); \ - DST_T *dst = (DST_T *)(ds->data + (line*ds->linesize) + (x*ds->depth/8)); \ - int col; \ - for (col = x ; col < w ; col++) { \ - *dst = (((*src >> RRS)&RM) << RLS) | \ - (((*src >> GRS)&GM) << GLS) | \ - (((*src >> GRS)&BM) << BLS); \ - src++; \ - dst++; \ - } \ - } - - -/* This copies data from the guest framebuffer region, into QEMU''s copy - * NB. QEMU''s copy is stored in the pixel format of a) the local X server (SDL case) - * or b) the current VNC client pixel format. - */ -static void xen_pvfb_guest_copy(struct xenfb *xenfb, int x, int y, int w, int h) -{ - DisplayState *ds = (DisplayState *)xenfb->user_data; - int line; - - if (xenfb->depth == ds->depth) { /* Perfect match can use fast path */ - for (line = y ; line < (y+h) ; line++) { - memcpy(ds->data + (line * ds->linesize) + (x*ds->depth/8), - xenfb->pixels + (line*xenfb->row_stride) + (x*xenfb->depth/8), - w * xenfb->depth/8); - } - } else { /* Mismatch requires slow pixel munging */ - if (xenfb->depth == 8) { - /* 8 bit source == r:3 g:3 b:2 */ - if (ds->depth == 16) { - BLT(uint8_t, uint16_t, 5, 2, 0, 11, 5, 0, 7, 7, 3); - } else if (ds->depth == 32) { - BLT(uint8_t, uint32_t, 5, 2, 0, 16, 8, 0, 7, 7, 3); - } - } else if (xenfb->depth == 16) { - /* 16 bit source == r:5 g:6 b:5 */ - if (ds->depth == 8) { - BLT(uint16_t, uint8_t, 11, 5, 0, 5, 2, 0, 31, 63, 31); - } else if (ds->depth == 32) { - BLT(uint16_t, uint32_t, 11, 5, 0, 16, 8, 0, 31, 63, 31); - } - } else if (xenfb->depth == 32) { - /* 32 bit source == r:8 g:8 b:8 (padding:8) */ - if (ds->depth == 8) { - BLT(uint32_t, uint8_t, 16, 8, 0, 5, 2, 0, 255, 255, 255); - } else if (ds->depth == 16) { - BLT(uint32_t, uint16_t, 16, 8, 0, 11, 5, 0, 255, 255, 255); - } - } - } - dpy_update(ds, x, y, w, h); -} - - -/* Send a keypress from the client to the guest OS */ -static void xen_pvfb_put_keycode(void *opaque, int keycode) -{ - struct xenfb *xenfb = (struct xenfb*)opaque; - xenfb_send_key(xenfb, keycode & 0x80 ? 0 : 1, keycode & 0x7f); -} - -/* Send a mouse event from the client to the guest OS */ -static void xen_pvfb_mouse_event(void *opaque, - int dx, int dy, int dz, int button_state) -{ - static int old_state = 0; - int i; - struct xenfb *xenfb = (struct xenfb*)opaque; - DisplayState *ds = (DisplayState *)xenfb->user_data; - if (xenfb->abs_pointer_wanted) - xenfb_send_position(xenfb, - dx*ds->width/0x7fff, - dy*ds->height/0x7fff); - else - xenfb_send_motion(xenfb, dx, dy); - - for (i = 0 ; i < 8 ; i++) { - int lastDown = old_state & (1 << i); - int down = button_state & (1 << i); - if (down == lastDown) - continue; - - if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0) - return; - } - old_state = button_state; -} - -/* QEMU display state changed, so refresh the framebuffer copy */ -void xen_pvfb_update(void *opaque) -{ - struct xenfb *xenfb = (struct xenfb *)opaque; - xen_pvfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height); -} - -/* QEMU display state changed, so refresh the framebuffer copy */ -void xen_pvfb_invalidate(void *opaque) -{ - struct xenfb *xenfb = (struct xenfb *)opaque; - xen_pvfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height); -} - -/* Screen dump is not used in Xen, so no need to impl this ? */ -void xen_pvfb_screen_dump(void *opaque, const char *name) { } /* The Xen PV machine currently provides @@ -160,30 +49,11 @@ static void xen_init_pv(uint64_t ram_siz } /* Talk to the guest */ - if (xenfb_attach_dom(xenfb, domid) < 0) { + if (xenfb_attach_dom(xenfb, domid, ds) < 0) { fprintf(stderr, "Could not connect to domain (%s)\n", strerror(errno)); exit(1); } - xenfb->update = xen_pvfb_guest_copy; - xenfb->user_data = ds; - - /* Tell QEMU to allocate a graphical console */ - graphic_console_init(ds, - xen_pvfb_update, - xen_pvfb_invalidate, - xen_pvfb_screen_dump, - xenfb); - - /* Register our keyboard & mouse handlers */ - qemu_add_kbd_event_handler(xen_pvfb_put_keycode, xenfb); - qemu_add_mouse_event_handler(xen_pvfb_mouse_event, xenfb, - xenfb->abs_pointer_wanted, - "Xen PVFB Mouse"); - - - /* Setup QEMU display */ - dpy_resize(ds, xenfb->width, xenfb->height); } QEMUMachine xenpv_machine = { diff -r c2aa6c7965a3 tools/ioemu/hw/xenfb.c --- a/tools/ioemu/hw/xenfb.c Wed Aug 15 14:17:30 2007 -0400 +++ b/tools/ioemu/hw/xenfb.c Tue Aug 21 22:04:25 2007 -0400 @@ -16,8 +16,8 @@ #include <string.h> #include <time.h> #include <xs.h> - -#include "vl.h" +#include <linux/input.h> + #include "xenfb.h" // FIXME defend against malicious frontend? @@ -586,6 +586,177 @@ static int xenfb_on_state_change(struct return 0; } +static int xenfb_kbd_event(struct xenfb_private *xenfb, + union xenkbd_in_event *event) +{ + uint32_t prod; + struct xenkbd_page *page = xenfb->kbd.page; + + if (xenfb->kbd.state != XenbusStateConnected) + return 0; + + prod = page->in_prod; + if (prod - page->in_cons == XENKBD_IN_RING_LEN) { + errno = EAGAIN; + return -1; + } + + mb(); /* ensure ring space available */ + XENKBD_IN_RING_REF(page, prod) = *event; + wmb(); /* ensure ring contents visible */ + page->in_prod = prod + 1; + return xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port); +} + +static int xenfb_send_key(struct xenfb *xenfb_pub, bool down, int keycode) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + union xenkbd_in_event event; + + memset(&event, 0, XENKBD_IN_EVENT_SIZE); + event.type = XENKBD_TYPE_KEY; + event.key.pressed = down ? 1 : 0; + event.key.keycode = keycode; + + return xenfb_kbd_event(xenfb, &event); +} + +static int xenfb_send_motion(struct xenfb *xenfb_pub, int rel_x, int rel_y) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + union xenkbd_in_event event; + + memset(&event, 0, XENKBD_IN_EVENT_SIZE); + event.type = XENKBD_TYPE_MOTION; + event.motion.rel_x = rel_x; + event.motion.rel_y = rel_y; + + return xenfb_kbd_event(xenfb, &event); +} + +static int xenfb_send_position(struct xenfb *xenfb_pub, int abs_x, int abs_y) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + union xenkbd_in_event event; + + memset(&event, 0, XENKBD_IN_EVENT_SIZE); + event.type = XENKBD_TYPE_POS; + event.pos.abs_x = abs_x; + event.pos.abs_y = abs_y; + + return xenfb_kbd_event(xenfb, &event); +} + +/* Send a keypress from the client to the guest OS */ +static void xenfb_put_keycode(void *opaque, int keycode) +{ + struct xenfb *xenfb = (struct xenfb*)opaque; + xenfb_send_key(xenfb, keycode & 0x80 ? 0 : 1, keycode & 0x7f); +} + +/* Send a mouse event from the client to the guest OS */ +static void xenfb_mouse_event(void *opaque, + int dx, int dy, int dz, int button_state) +{ + int i; + struct xenfb *xenfb = (struct xenfb*)opaque; + DisplayState *ds = (DisplayState *)xenfb->user_data; + if (xenfb->abs_pointer_wanted) + xenfb_send_position(xenfb, + dx*ds->width/0x7fff, + dy*ds->height/0x7fff); + else + xenfb_send_motion(xenfb, dx, dy); + + for (i = 0 ; i < 8 ; i++) { + int lastDown = xenfb->button_state & (1 << i); + int down = button_state & (1 << i); + if (down == lastDown) + continue; + + if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0) + return; + } + xenfb->button_state = button_state; +} + +/* A convenient function for munging pixels between different depths */ +#define BLT(SRC_T,DST_T,RLS,GLS,BLS,RRS,GRS,BRS,RM,GM,BM) \ + for (line = y ; line < h ; line++) { \ + SRC_T *src = (SRC_T *)(xenfb->pixels + (line*xenfb->row_stride) + (x*xenfb->depth/8)); \ + DST_T *dst = (DST_T *)(ds->data + (line*ds->linesize) + (x*ds->depth/8)); \ + int col; \ + for (col = x ; col < w ; col++) { \ + *dst = (((*src >> RRS)&RM) << RLS) | \ + (((*src >> GRS)&GM) << GLS) | \ + (((*src >> GRS)&BM) << BLS); \ + src++; \ + dst++; \ + } \ + } + + +/* This copies data from the guest framebuffer region, into QEMU''s copy + * NB. QEMU''s copy is stored in the pixel format of a) the local X server (SDL case) + * or b) the current VNC client pixel format. + */ +static void xenfb_guest_copy(struct xenfb *xenfb, int x, int y, int w, int h) +{ + DisplayState *ds = (DisplayState *)xenfb->user_data; + int line; + + if (xenfb->depth == ds->depth) { /* Perfect match can use fast path */ + for (line = y ; line < (y+h) ; line++) { + memcpy(ds->data + (line * ds->linesize) + (x*ds->depth/8), + xenfb->pixels + (line*xenfb->row_stride) + (x*xenfb->depth/8), + w * xenfb->depth/8); + } + } else { /* Mismatch requires slow pixel munging */ + if (xenfb->depth == 8) { + /* 8 bit source == r:3 g:3 b:2 */ + if (ds->depth == 16) { + BLT(uint8_t, uint16_t, 5, 2, 0, 11, 5, 0, 7, 7, 3); + } else if (ds->depth == 32) { + BLT(uint8_t, uint32_t, 5, 2, 0, 16, 8, 0, 7, 7, 3); + } + } else if (xenfb->depth == 16) { + /* 16 bit source == r:5 g:6 b:5 */ + if (ds->depth == 8) { + BLT(uint16_t, uint8_t, 11, 5, 0, 5, 2, 0, 31, 63, 31); + } else if (ds->depth == 32) { + BLT(uint16_t, uint32_t, 11, 5, 0, 16, 8, 0, 31, 63, 31); + } + } else if (xenfb->depth == 32) { + /* 32 bit source == r:8 g:8 b:8 (padding:8) */ + if (ds->depth == 8) { + BLT(uint32_t, uint8_t, 16, 8, 0, 5, 2, 0, 255, 255, 255); + } else if (ds->depth == 16) { + BLT(uint32_t, uint16_t, 16, 8, 0, 11, 5, 0, 255, 255, 255); + } + } + } + dpy_update(ds, x, y, w, h); +} + +/* QEMU display state changed, so refresh the framebuffer copy */ +static void xenfb_update(void *opaque) +{ + struct xenfb *xenfb = (struct xenfb *)opaque; + xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height); +} + +/* QEMU display state changed, so refresh the framebuffer copy */ +static void xenfb_invalidate(void *opaque) +{ + struct xenfb *xenfb = (struct xenfb *)opaque; + xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height); +} + +/* Screen dump is not used in Xen, so no need to impl this ? */ +static void xenfb_screen_dump(void *opaque, const char *name) { } + + + static void xenfb_dispatch_channel(void *xenfb_pub) { struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; @@ -620,7 +791,7 @@ static void xenfb_dispatch_store(void *x } -int xenfb_attach_dom(struct xenfb *xenfb_pub, int domid) +int xenfb_attach_dom(struct xenfb *xenfb_pub, int domid, DisplayState *ds) { struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; struct xs_handle *xsh = xenfb->xsh; @@ -708,6 +879,23 @@ int xenfb_attach_dom(struct xenfb *xenfb if (qemu_set_fd_handler2(xc_evtchn_fd(xenfb->evt_xch), NULL, xenfb_dispatch_channel, NULL, xenfb) < 0) goto error; + /* Register our keyboard & mouse handlers */ + qemu_add_kbd_event_handler(xenfb_put_keycode, xenfb); + qemu_add_mouse_event_handler(xenfb_mouse_event, xenfb, + xenfb_pub->abs_pointer_wanted, + "Xen PVFB Mouse"); + + xenfb_pub->update = xenfb_guest_copy; + xenfb_pub->user_data = ds; + + /* Tell QEMU to allocate a graphical console */ + graphic_console_init(ds, + xenfb_update, + xenfb_invalidate, + xenfb_screen_dump, + xenfb_pub); + dpy_resize(ds, xenfb_pub->width, xenfb_pub->height); + return 0; error: @@ -719,66 +907,6 @@ int xenfb_attach_dom(struct xenfb *xenfb return -1; } -static int xenfb_kbd_event(struct xenfb_private *xenfb, - union xenkbd_in_event *event) -{ - uint32_t prod; - struct xenkbd_page *page = xenfb->kbd.page; - - if (xenfb->kbd.state != XenbusStateConnected) - return 0; - - prod = page->in_prod; - if (prod - page->in_cons == XENKBD_IN_RING_LEN) { - errno = EAGAIN; - return -1; - } - - mb(); /* ensure ring space available */ - XENKBD_IN_RING_REF(page, prod) = *event; - wmb(); /* ensure ring contents visible */ - page->in_prod = prod + 1; - return xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port); -} - -int xenfb_send_key(struct xenfb *xenfb_pub, bool down, int keycode) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - union xenkbd_in_event event; - - memset(&event, 0, XENKBD_IN_EVENT_SIZE); - event.type = XENKBD_TYPE_KEY; - event.key.pressed = down ? 1 : 0; - event.key.keycode = keycode; - - return xenfb_kbd_event(xenfb, &event); -} - -int xenfb_send_motion(struct xenfb *xenfb_pub, int rel_x, int rel_y) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - union xenkbd_in_event event; - - memset(&event, 0, XENKBD_IN_EVENT_SIZE); - event.type = XENKBD_TYPE_MOTION; - event.motion.rel_x = rel_x; - event.motion.rel_y = rel_y; - - return xenfb_kbd_event(xenfb, &event); -} - -int xenfb_send_position(struct xenfb *xenfb_pub, int abs_x, int abs_y) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - union xenkbd_in_event event; - - memset(&event, 0, XENKBD_IN_EVENT_SIZE); - event.type = XENKBD_TYPE_POS; - event.pos.abs_x = abs_x; - event.pos.abs_y = abs_y; - - return xenfb_kbd_event(xenfb, &event); -} /* * Local variables: * c-indent-level: 8 diff -r c2aa6c7965a3 tools/ioemu/hw/xenfb.h --- a/tools/ioemu/hw/xenfb.h Wed Aug 15 14:17:30 2007 -0400 +++ b/tools/ioemu/hw/xenfb.h Tue Aug 21 22:03:27 2007 -0400 @@ -1,6 +1,7 @@ #ifndef _XENFB_H_ #define _XENFB_H_ +#include "vl.h" #include <stdbool.h> #include <sys/types.h> @@ -13,6 +14,7 @@ struct xenfb int width; int height; int abs_pointer_wanted; + int button_state; void *user_data; @@ -23,10 +25,6 @@ void xenfb_delete(struct xenfb *xenfb); void xenfb_delete(struct xenfb *xenfb); void xenfb_teardown(struct xenfb *xenfb); -int xenfb_attach_dom(struct xenfb *xenfb, int domid); - -int xenfb_send_key(struct xenfb *xenfb, bool down, int keycode); -int xenfb_send_motion(struct xenfb *xenfb, int rel_x, int rel_y); -int xenfb_send_position(struct xenfb *xenfb, int abs_x, int abs_y); +int xenfb_attach_dom(struct xenfb *xenfb, int domid, DisplayState *ds); #endif -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=| _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel P. Berrange
2007-Aug-22 22:31 UTC
Re: [Xen-devel] PATCH: 6/10: Merge private & public xenfb structs
This patch merges the public & private structs from the paravirt FB into a single struct. Since QEMU is the only consumer of this code there is no need for the artifical pub/priv split. Merging the two will make it possible to more tightly integrate with QEMU''s event loop and do asynchronous non-blocking negoiation with the frontend devices (see next patch). xenfb.c | 273 ++++++++++++++++++++++++++++++++-------------------------------- xenfb.h | 16 --- 2 files changed, 139 insertions(+), 150 deletions(-) Signed-off-by: Daniel P. Berrange <berrange@redhat.com> Dan. diff -r 231a22d0b7dd tools/ioemu/hw/xenfb.c --- a/tools/ioemu/hw/xenfb.c Tue Aug 21 22:04:29 2007 -0400 +++ b/tools/ioemu/hw/xenfb.c Tue Aug 21 22:07:36 2007 -0400 @@ -22,6 +22,8 @@ // FIXME defend against malicious frontend? +struct xenfb; + struct xenfb_device { const char *devicetype; char nodename[64]; /* backend xenstore dir */ @@ -30,20 +32,33 @@ struct xenfb_device { enum xenbus_state state; /* backend state */ void *page; /* shared page */ evtchn_port_t port; - struct xenfb_private *xenfb; + struct xenfb *xenfb; }; -struct xenfb_private { - struct xenfb pub; +struct xenfb_data +{ + void *pixels; + size_t len; + + int row_stride; + int depth; + int width; + int height; + int abs_pointer_wanted; +}; + +struct xenfb { + DisplayState *ds; int evt_xch; /* event channel driver handle */ int xc; /* hypervisor interface handle */ struct xs_handle *xsh; /* xs daemon handle */ struct xenfb_device fb, kbd; - size_t fb_len; /* size of framebuffer */ + struct xenfb_data data; char protocol[64]; /* frontend protocol */ + int button_state; }; -static void xenfb_detach_dom(struct xenfb_private *); +static void xenfb_detach_dom(struct xenfb *); static char *xenfb_path_in_dom(struct xs_handle *xsh, char *buf, size_t size, @@ -124,7 +139,7 @@ static int xenfb_xs_printf(struct xs_han static void xenfb_device_init(struct xenfb_device *dev, const char *type, - struct xenfb_private *xenfb) + struct xenfb *xenfb) { dev->devicetype = type; dev->otherend_id = -1; @@ -132,19 +147,17 @@ static void xenfb_device_init(struct xen dev->xenfb = xenfb; } -int xenfb_device_set_domain(struct xenfb_device *dev, int domid) -{ - struct xenfb_private *xenfb = dev->xenfb; - +static int xenfb_device_set_domain(struct xenfb_device *dev, int domid) +{ dev->otherend_id = domid; - if (!xenfb_path_in_dom(xenfb->xsh, + if (!xenfb_path_in_dom(dev->xenfb->xsh, dev->otherend, sizeof(dev->otherend), domid, "device/%s/0", dev->devicetype)) { errno = ENOENT; return -1; } - if (!xenfb_path_in_dom(xenfb->xsh, + if (!xenfb_path_in_dom(dev->xenfb->xsh, dev->nodename, sizeof(dev->nodename), 0, "backend/%s/%d/0", dev->devicetype, domid)) { errno = ENOENT; @@ -156,8 +169,8 @@ int xenfb_device_set_domain(struct xenfb struct xenfb *xenfb_new(void) { - struct xenfb_private *xenfb = malloc(sizeof(*xenfb)); int serrno; + struct xenfb *xenfb = qemu_malloc(sizeof(struct xenfb)); if (xenfb == NULL) return NULL; @@ -179,30 +192,26 @@ struct xenfb *xenfb_new(void) if (!xenfb->xsh) goto fail; - return &xenfb->pub; + return xenfb; fail: serrno = errno; - xenfb_delete(&xenfb->pub); + xenfb_delete(xenfb); errno = serrno; return NULL; } /* Remove the backend area in xenbus since the framebuffer really is going away. */ -void xenfb_teardown(struct xenfb *xenfb_pub) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - +void xenfb_teardown(struct xenfb *xenfb) +{ xs_rm(xenfb->xsh, XBT_NULL, xenfb->fb.nodename); xs_rm(xenfb->xsh, XBT_NULL, xenfb->kbd.nodename); } -void xenfb_delete(struct xenfb *xenfb_pub) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - +void xenfb_delete(struct xenfb *xenfb) +{ xenfb_detach_dom(xenfb); if (xenfb->xc >= 0) xc_interface_close(xenfb->xc); @@ -334,7 +343,7 @@ static void xenfb_copy_mfns(int mode, in dst[i] = (mode == 32) ? src32[i] : src64[i]; } -static int xenfb_map_fb(struct xenfb_private *xenfb, int domid) +static int xenfb_map_fb(struct xenfb *xenfb, int domid) { struct xenfb_page *page = xenfb->fb.page; int n_fbmfns; @@ -389,7 +398,7 @@ static int xenfb_map_fb(struct xenfb_pri #endif } - n_fbmfns = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE; + n_fbmfns = (xenfb->data.len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE; n_fbdirs = n_fbmfns * mode / 8; n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE; @@ -412,9 +421,9 @@ static int xenfb_map_fb(struct xenfb_pri xenfb_copy_mfns(mode, n_fbmfns, fbmfns, map); munmap(map, n_fbdirs * XC_PAGE_SIZE); - xenfb->pub.pixels = xc_map_foreign_batch(xenfb->xc, domid, + xenfb->data.pixels = xc_map_foreign_batch(xenfb->xc, domid, PROT_READ | PROT_WRITE, fbmfns, n_fbmfns); - if (xenfb->pub.pixels == NULL) + if (xenfb->data.pixels == NULL) goto out; ret = 0; /* all is fine */ @@ -429,7 +438,7 @@ static int xenfb_map_fb(struct xenfb_pri static int xenfb_bind(struct xenfb_device *dev) { - struct xenfb_private *xenfb = dev->xenfb; + struct xenfb *xenfb = dev->xenfb; unsigned long mfn; evtchn_port_t evtchn; @@ -512,17 +521,74 @@ static void xenfb_dev_fatal(struct xenfb } -static void xenfb_detach_dom(struct xenfb_private *xenfb) +static void xenfb_detach_dom(struct xenfb *xenfb) { xenfb_unbind(&xenfb->fb); xenfb_unbind(&xenfb->kbd); - if (xenfb->pub.pixels) { - munmap(xenfb->pub.pixels, xenfb->fb_len); - xenfb->pub.pixels = NULL; - } -} - -static void xenfb_on_fb_event(struct xenfb_private *xenfb) + if (xenfb->data.pixels) { + munmap(xenfb->data.pixels, xenfb->data.len); + xenfb->data.pixels = NULL; + } +} + +/* A convenient function for munging pixels between different depths */ +#define BLT(SRC_T,DST_T,RLS,GLS,BLS,RRS,GRS,BRS,RM,GM,BM) \ + for (line = y ; line < h ; line++) { \ + SRC_T *src = (SRC_T *)(xenfb->data.pixels + (line*xenfb->data.row_stride) + (x*xenfb->data.depth/8)); \ + DST_T *dst = (DST_T *)(xenfb->ds->data + (line*xenfb->ds->linesize) + (x*xenfb->ds->depth/8)); \ + int col; \ + for (col = x ; col < w ; col++) { \ + *dst = (((*src >> RRS)&RM) << RLS) | \ + (((*src >> GRS)&GM) << GLS) | \ + (((*src >> GRS)&BM) << BLS); \ + src++; \ + dst++; \ + } \ + } + + +/* This copies data from the guest framebuffer region, into QEMU''s copy + * NB. QEMU''s copy is stored in the pixel format of a) the local X server (SDL case) + * or b) the current VNC client pixel format. + */ +static void xenfb_guest_copy(struct xenfb *xenfb, int x, int y, int w, int h) +{ + int line; + + if (xenfb->data.depth == xenfb->ds->depth) { /* Perfect match can use fast path */ + for (line = y ; line < (y+h) ; line++) { + memcpy(xenfb->ds->data + (line * xenfb->ds->linesize) + (x*xenfb->ds->depth/8), + xenfb->data.pixels + (line*xenfb->data.row_stride) + (x*xenfb->data.depth/8), + w * xenfb->data.depth/8); + } + } else { /* Mismatch requires slow pixel munging */ + if (xenfb->data.depth == 8) { + /* 8 bit source == r:3 g:3 b:2 */ + if (xenfb->ds->depth == 16) { + BLT(uint8_t, uint16_t, 5, 2, 0, 11, 5, 0, 7, 7, 3); + } else if (xenfb->ds->depth == 32) { + BLT(uint8_t, uint32_t, 5, 2, 0, 16, 8, 0, 7, 7, 3); + } + } else if (xenfb->data.depth == 16) { + /* 16 bit source == r:5 g:6 b:5 */ + if (xenfb->ds->depth == 8) { + BLT(uint16_t, uint8_t, 11, 5, 0, 5, 2, 0, 31, 63, 31); + } else if (xenfb->ds->depth == 32) { + BLT(uint16_t, uint32_t, 11, 5, 0, 16, 8, 0, 31, 63, 31); + } + } else if (xenfb->data.depth == 32) { + /* 32 bit source == r:8 g:8 b:8 (padding:8) */ + if (xenfb->ds->depth == 8) { + BLT(uint32_t, uint8_t, 16, 8, 0, 5, 2, 0, 255, 255, 255); + } else if (xenfb->ds->depth == 16) { + BLT(uint32_t, uint16_t, 16, 8, 0, 11, 5, 0, 255, 255, 255); + } + } + } + dpy_update(xenfb->ds, x, y, w, h); +} + +static void xenfb_on_fb_event(struct xenfb *xenfb) { uint32_t prod, cons; struct xenfb_page *page = xenfb->fb.page; @@ -536,11 +602,10 @@ static void xenfb_on_fb_event(struct xen switch (event->type) { case XENFB_TYPE_UPDATE: - if (xenfb->pub.update) - xenfb->pub.update(&xenfb->pub, - event->update.x, event->update.y, - event->update.width, event->update.height); - break; + xenfb_guest_copy(xenfb, + event->update.x, event->update.y, + event->update.width, event->update.height); + break; } } mb(); /* ensure we''re done with ring contents */ @@ -548,7 +613,7 @@ static void xenfb_on_fb_event(struct xen xc_evtchn_notify(xenfb->evt_xch, xenfb->fb.port); } -static void xenfb_on_kbd_event(struct xenfb_private *xenfb) +static void xenfb_on_kbd_event(struct xenfb *xenfb) { struct xenkbd_page *page = xenfb->kbd.page; @@ -586,7 +651,7 @@ static int xenfb_on_state_change(struct return 0; } -static int xenfb_kbd_event(struct xenfb_private *xenfb, +static int xenfb_kbd_event(struct xenfb *xenfb, union xenkbd_in_event *event) { uint32_t prod; @@ -608,9 +673,8 @@ static int xenfb_kbd_event(struct xenfb_ return xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port); } -static int xenfb_send_key(struct xenfb *xenfb_pub, bool down, int keycode) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; +static int xenfb_send_key(struct xenfb *xenfb, bool down, int keycode) +{ union xenkbd_in_event event; memset(&event, 0, XENKBD_IN_EVENT_SIZE); @@ -621,9 +685,8 @@ static int xenfb_send_key(struct xenfb * return xenfb_kbd_event(xenfb, &event); } -static int xenfb_send_motion(struct xenfb *xenfb_pub, int rel_x, int rel_y) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; +static int xenfb_send_motion(struct xenfb *xenfb, int rel_x, int rel_y) +{ union xenkbd_in_event event; memset(&event, 0, XENKBD_IN_EVENT_SIZE); @@ -634,9 +697,8 @@ static int xenfb_send_motion(struct xenf return xenfb_kbd_event(xenfb, &event); } -static int xenfb_send_position(struct xenfb *xenfb_pub, int abs_x, int abs_y) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; +static int xenfb_send_position(struct xenfb *xenfb, int abs_x, int abs_y) +{ union xenkbd_in_event event; memset(&event, 0, XENKBD_IN_EVENT_SIZE); @@ -660,11 +722,11 @@ static void xenfb_mouse_event(void *opaq { int i; struct xenfb *xenfb = (struct xenfb*)opaque; - DisplayState *ds = (DisplayState *)xenfb->user_data; - if (xenfb->abs_pointer_wanted) + + if (xenfb->data.abs_pointer_wanted) xenfb_send_position(xenfb, - dx*ds->width/0x7fff, - dy*ds->height/0x7fff); + dx*xenfb->ds->width/0x7fff, + dy*xenfb->ds->height/0x7fff); else xenfb_send_motion(xenfb, dx, dy); @@ -680,76 +742,19 @@ static void xenfb_mouse_event(void *opaq xenfb->button_state = button_state; } -/* A convenient function for munging pixels between different depths */ -#define BLT(SRC_T,DST_T,RLS,GLS,BLS,RRS,GRS,BRS,RM,GM,BM) \ - for (line = y ; line < h ; line++) { \ - SRC_T *src = (SRC_T *)(xenfb->pixels + (line*xenfb->row_stride) + (x*xenfb->depth/8)); \ - DST_T *dst = (DST_T *)(ds->data + (line*ds->linesize) + (x*ds->depth/8)); \ - int col; \ - for (col = x ; col < w ; col++) { \ - *dst = (((*src >> RRS)&RM) << RLS) | \ - (((*src >> GRS)&GM) << GLS) | \ - (((*src >> GRS)&BM) << BLS); \ - src++; \ - dst++; \ - } \ - } - - -/* This copies data from the guest framebuffer region, into QEMU''s copy - * NB. QEMU''s copy is stored in the pixel format of a) the local X server (SDL case) - * or b) the current VNC client pixel format. - */ -static void xenfb_guest_copy(struct xenfb *xenfb, int x, int y, int w, int h) -{ - DisplayState *ds = (DisplayState *)xenfb->user_data; - int line; - - if (xenfb->depth == ds->depth) { /* Perfect match can use fast path */ - for (line = y ; line < (y+h) ; line++) { - memcpy(ds->data + (line * ds->linesize) + (x*ds->depth/8), - xenfb->pixels + (line*xenfb->row_stride) + (x*xenfb->depth/8), - w * xenfb->depth/8); - } - } else { /* Mismatch requires slow pixel munging */ - if (xenfb->depth == 8) { - /* 8 bit source == r:3 g:3 b:2 */ - if (ds->depth == 16) { - BLT(uint8_t, uint16_t, 5, 2, 0, 11, 5, 0, 7, 7, 3); - } else if (ds->depth == 32) { - BLT(uint8_t, uint32_t, 5, 2, 0, 16, 8, 0, 7, 7, 3); - } - } else if (xenfb->depth == 16) { - /* 16 bit source == r:5 g:6 b:5 */ - if (ds->depth == 8) { - BLT(uint16_t, uint8_t, 11, 5, 0, 5, 2, 0, 31, 63, 31); - } else if (ds->depth == 32) { - BLT(uint16_t, uint32_t, 11, 5, 0, 16, 8, 0, 31, 63, 31); - } - } else if (xenfb->depth == 32) { - /* 32 bit source == r:8 g:8 b:8 (padding:8) */ - if (ds->depth == 8) { - BLT(uint32_t, uint8_t, 16, 8, 0, 5, 2, 0, 255, 255, 255); - } else if (ds->depth == 16) { - BLT(uint32_t, uint16_t, 16, 8, 0, 11, 5, 0, 255, 255, 255); - } - } - } - dpy_update(ds, x, y, w, h); -} /* QEMU display state changed, so refresh the framebuffer copy */ static void xenfb_update(void *opaque) { struct xenfb *xenfb = (struct xenfb *)opaque; - xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height); + xenfb_guest_copy(xenfb, 0, 0, xenfb->data.width, xenfb->data.height); } /* QEMU display state changed, so refresh the framebuffer copy */ static void xenfb_invalidate(void *opaque) { struct xenfb *xenfb = (struct xenfb *)opaque; - xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height); + xenfb_guest_copy(xenfb, 0, 0, xenfb->data.width, xenfb->data.height); } /* Screen dump is not used in Xen, so no need to impl this ? */ @@ -757,9 +762,9 @@ static void xenfb_screen_dump(void *opaq -static void xenfb_dispatch_channel(void *xenfb_pub) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; +static void xenfb_dispatch_channel(void *opaque) +{ + struct xenfb *xenfb = (struct xenfb *)opaque; evtchn_port_t port; port = xc_evtchn_pending(xenfb->evt_xch); if (port == -1) @@ -774,9 +779,9 @@ static void xenfb_dispatch_channel(void exit(1); } -static void xenfb_dispatch_store(void *xenfb_pub) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; +static void xenfb_dispatch_store(void *opaque) +{ + struct xenfb *xenfb = (struct xenfb *)opaque; unsigned dummy; char **vec; int r; @@ -791,9 +796,8 @@ static void xenfb_dispatch_store(void *x } -int xenfb_attach_dom(struct xenfb *xenfb_pub, int domid, DisplayState *ds) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; +int xenfb_attach_dom(struct xenfb *xenfb, int domid, DisplayState *ds) +{ struct xs_handle *xsh = xenfb->xsh; int val, serrno; struct xenfb_page *fb_page; @@ -849,12 +853,12 @@ int xenfb_attach_dom(struct xenfb *xenfb /* TODO check for permitted ranges */ fb_page = xenfb->fb.page; - xenfb->pub.depth = fb_page->depth; - xenfb->pub.width = fb_page->width; - xenfb->pub.height = fb_page->height; + xenfb->data.depth = fb_page->depth; + xenfb->data.width = fb_page->width; + xenfb->data.height = fb_page->height; /* TODO check for consistency with the above */ - xenfb->fb_len = fb_page->mem_length; - xenfb->pub.row_stride = fb_page->line_length; + xenfb->data.len = fb_page->mem_length; + xenfb->data.row_stride = fb_page->line_length; if (xenfb_map_fb(xenfb, domid) < 0) goto error; @@ -869,7 +873,7 @@ int xenfb_attach_dom(struct xenfb *xenfb if (xenfb_xs_scanf1(xsh, xenfb->kbd.otherend, "request-abs-pointer", "%d", &val) < 0) val = 0; - xenfb->pub.abs_pointer_wanted = val; + xenfb->data.abs_pointer_wanted = val; /* Listen for events from xenstore */ if (qemu_set_fd_handler2(xs_fileno(xenfb->xsh), NULL, xenfb_dispatch_store, NULL, xenfb) < 0) @@ -882,19 +886,18 @@ int xenfb_attach_dom(struct xenfb *xenfb /* Register our keyboard & mouse handlers */ qemu_add_kbd_event_handler(xenfb_put_keycode, xenfb); qemu_add_mouse_event_handler(xenfb_mouse_event, xenfb, - xenfb_pub->abs_pointer_wanted, + xenfb->data.abs_pointer_wanted, "Xen PVFB Mouse"); - xenfb_pub->update = xenfb_guest_copy; - xenfb_pub->user_data = ds; + xenfb->ds = ds; /* Tell QEMU to allocate a graphical console */ graphic_console_init(ds, xenfb_update, xenfb_invalidate, xenfb_screen_dump, - xenfb_pub); - dpy_resize(ds, xenfb_pub->width, xenfb_pub->height); + xenfb); + dpy_resize(ds, xenfb->data.width, xenfb->data.height); return 0; diff -r 231a22d0b7dd tools/ioemu/hw/xenfb.h --- a/tools/ioemu/hw/xenfb.h Tue Aug 21 22:04:29 2007 -0400 +++ b/tools/ioemu/hw/xenfb.h Tue Aug 21 22:04:43 2007 -0400 @@ -5,21 +5,7 @@ #include <stdbool.h> #include <sys/types.h> -struct xenfb -{ - void *pixels; - - int row_stride; - int depth; - int width; - int height; - int abs_pointer_wanted; - int button_state; - - void *user_data; - - void (*update)(struct xenfb *xenfb, int x, int y, int width, int height); -}; +struct xenfb; struct xenfb *xenfb_new(void); void xenfb_delete(struct xenfb *xenfb); -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=| _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel P. Berrange
2007-Aug-22 22:32 UTC
Re: [Xen-devel] PATCH: 7/10: Async negotiation with xenfb frontend
This patch re-factors the paravirt console xenfb_attach_dom method. The original method blocks the caller until the front & backends have both switched to the connected state. This isn''t an immediate problem, but patches which follow will extend qemu to also handle the text console so blocking on graphics console startup will block the text console processing. The new code is basically a state machine. It starts off with a watch waiting for the KBD backend to switch to ''initialized'' mode, then does the same for the FB backend. Now it waits for KBD & FB frontend devices to initialize, reading & mapping the framebuffer & its config at the appropriate step. When the KBD frontend finally reaches the connected state it registers a graphical console with QEMU and sets up the various framebuffer, mouse & keyboard event handlers. If a client connects to the VNC server before this is completed, then they will merely see a text console (or perhaps the monitor if configured that way). xen_machine_pv.c | 9 xenfb.c | 752 ++++++++++++++++++++++++++++++++----------------------- xenfb.h | 7 3 files changed, 445 insertions(+), 323 deletions(-) Signed-off-by: Daniel P. Berrange <berrange@redhat.com> Dan. diff -r 829464d36542 tools/ioemu/hw/xen_machine_pv.c --- a/tools/ioemu/hw/xen_machine_pv.c Tue Aug 21 22:07:47 2007 -0400 +++ b/tools/ioemu/hw/xen_machine_pv.c Tue Aug 21 22:08:24 2007 -0400 @@ -41,16 +41,9 @@ static void xen_init_pv(uint64_t ram_siz extern int domid; /* Prepare PVFB state */ - xenfb = xenfb_new(); + xenfb = xenfb_new(domid, ds); if (xenfb == NULL) { fprintf(stderr, "Could not create framebuffer (%s)\n", - strerror(errno)); - exit(1); - } - - /* Talk to the guest */ - if (xenfb_attach_dom(xenfb, domid, ds) < 0) { - fprintf(stderr, "Could not connect to domain (%s)\n", strerror(errno)); exit(1); } diff -r 829464d36542 tools/ioemu/hw/xenfb.c --- a/tools/ioemu/hw/xenfb.c Tue Aug 21 22:07:47 2007 -0400 +++ b/tools/ioemu/hw/xenfb.c Tue Aug 21 22:14:04 2007 -0400 @@ -19,6 +19,12 @@ #include <linux/input.h> #include "xenfb.h" +#define DEBUG 1 +#if DEBUG +#define LOGF(msg,...) fprintf(stderr, msg, ## __VA_ARGS__) +#else +#define LOGF(msg,...) do { } while (0) +#endif // FIXME defend against malicious frontend? @@ -167,60 +173,6 @@ static int xenfb_device_set_domain(struc return 0; } -struct xenfb *xenfb_new(void) -{ - int serrno; - struct xenfb *xenfb = qemu_malloc(sizeof(struct xenfb)); - - if (xenfb == NULL) - return NULL; - - memset(xenfb, 0, sizeof(*xenfb)); - xenfb->evt_xch = xenfb->xc = -1; - xenfb_device_init(&xenfb->fb, "vfb", xenfb); - xenfb_device_init(&xenfb->kbd, "vkbd", xenfb); - - xenfb->evt_xch = xc_evtchn_open(); - if (xenfb->evt_xch == -1) - goto fail; - - xenfb->xc = xc_interface_open(); - if (xenfb->xc == -1) - goto fail; - - xenfb->xsh = xs_daemon_open(); - if (!xenfb->xsh) - goto fail; - - return xenfb; - - fail: - serrno = errno; - xenfb_delete(xenfb); - errno = serrno; - return NULL; -} - -/* Remove the backend area in xenbus since the framebuffer really is - going away. */ -void xenfb_teardown(struct xenfb *xenfb) -{ - xs_rm(xenfb->xsh, XBT_NULL, xenfb->fb.nodename); - xs_rm(xenfb->xsh, XBT_NULL, xenfb->kbd.nodename); -} - - -void xenfb_delete(struct xenfb *xenfb) -{ - xenfb_detach_dom(xenfb); - if (xenfb->xc >= 0) - xc_interface_close(xenfb->xc); - if (xenfb->evt_xch >= 0) - xc_evtchn_close(xenfb->evt_xch); - if (xenfb->xsh) - xs_daemon_close(xenfb->xsh); - free(xenfb); -} static enum xenbus_state xenfb_read_state(struct xs_handle *xsh, const char *dir) @@ -228,6 +180,7 @@ static enum xenbus_state xenfb_read_stat int ret, state; ret = xenfb_xs_scanf1(xsh, dir, "state", "%d", &state); + LOGF("FB: read state %d %d\n", state, ret); if (ret < 0) return XenbusStateUnknown; @@ -240,65 +193,10 @@ static int xenfb_switch_state(struct xen enum xenbus_state state) { struct xs_handle *xsh = dev->xenfb->xsh; - + /*LOGF("FB: write state %d\n", state);*/ if (xenfb_xs_printf(xsh, dev->nodename, "state", "%d", state) < 0) return -1; dev->state = state; - return 0; -} - -static int xenfb_wait_for_state(struct xs_handle *xsh, const char *dir, - unsigned awaited) -{ - unsigned state, dummy; - char **vec; - - awaited |= 1 << XenbusStateUnknown; - - for (;;) { - state = xenfb_read_state(xsh, dir); - if ((1 << state) & awaited) - return state; - - vec = xs_read_watch(xsh, &dummy); - if (!vec) - return -1; - free(vec); - } -} - -static int xenfb_wait_for_backend_creation(struct xenfb_device *dev) -{ - struct xs_handle *xsh = dev->xenfb->xsh; - int state; - - if (!xs_watch(xsh, dev->nodename, "")) - return -1; - state = xenfb_wait_for_state(xsh, dev->nodename, - (1 << XenbusStateInitialising) - | (1 << XenbusStateClosed) -#if 1 /* TODO fudging state to permit restarting; to be removed */ - | (1 << XenbusStateInitWait) - | (1 << XenbusStateConnected) - | (1 << XenbusStateClosing) -#endif - ); - xs_unwatch(xsh, dev->nodename, ""); - - switch (state) { -#if 1 - case XenbusStateInitWait: - case XenbusStateConnected: - printf("Fudging state to %d\n", XenbusStateInitialising); /* FIXME */ -#endif - case XenbusStateInitialising: - case XenbusStateClosing: - case XenbusStateClosed: - break; - default: - return -1; - } - return 0; } @@ -310,28 +208,6 @@ static int xenfb_hotplug(struct xenfb_de return 0; } -static int xenfb_wait_for_frontend_initialised(struct xenfb_device *dev) -{ - switch (xenfb_wait_for_state(dev->xenfb->xsh, dev->otherend, -#if 1 /* TODO fudging state to permit restarting; to be removed */ - (1 << XenbusStateInitialised) - | (1 << XenbusStateConnected) -#else - 1 << XenbusStateInitialised, -#endif - )) { -#if 1 - case XenbusStateConnected: - printf("Fudging state to %d\n", XenbusStateInitialised); /* FIXME */ -#endif - case XenbusStateInitialised: - break; - default: - return -1; - } - - return 0; -} static void xenfb_copy_mfns(int mode, int count, unsigned long *dst, void *src) { @@ -474,52 +350,6 @@ static void xenfb_unbind(struct xenfb_de } } -static int xenfb_wait_for_frontend_connected(struct xenfb_device *dev) -{ - switch (xenfb_wait_for_state(dev->xenfb->xsh, dev->otherend, - 1 << XenbusStateConnected)) { - case XenbusStateConnected: - break; - default: - return -1; - } - - return 0; -} - -static void xenfb_dev_fatal(struct xenfb_device *dev, int err, - const char *fmt, ...) -{ - struct xs_handle *xsh = dev->xenfb->xsh; - va_list ap; - char errdir[80]; - char buf[1024]; - int n; - - fprintf(stderr, "%s ", dev->nodename); /* somewhat crude */ - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - if (err) - fprintf(stderr, " (%s)", strerror(err)); - putc(''\n'', stderr); - - if (!xenfb_path_in_dom(xsh, errdir, sizeof(errdir), 0, - "error/%s", dev->nodename)) - goto out; /* FIXME complain */ - - va_start(ap, fmt); - n = snprintf(buf, sizeof(buf), "%d ", err); - snprintf(buf + n, sizeof(buf) - n, fmt, ap); - va_end(ap); - - if (xenfb_xs_printf(xsh, buf, "error", "%s", buf) < 0) - goto out; /* FIXME complain */ - - out: - xenfb_switch_state(dev, XenbusStateClosing); -} - static void xenfb_detach_dom(struct xenfb *xenfb) { @@ -673,6 +503,8 @@ static int xenfb_kbd_event(struct xenfb return xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port); } + +/* Send a keyboard (or mouse button) event */ static int xenfb_send_key(struct xenfb *xenfb, bool down, int keycode) { union xenkbd_in_event event; @@ -685,10 +517,11 @@ static int xenfb_send_key(struct xenfb * return xenfb_kbd_event(xenfb, &event); } +/* Send a relative mouse movement event */ static int xenfb_send_motion(struct xenfb *xenfb, int rel_x, int rel_y) { union xenkbd_in_event event; - + LOGF("REL %d %d\n", rel_x, rel_y); memset(&event, 0, XENKBD_IN_EVENT_SIZE); event.type = XENKBD_TYPE_MOTION; event.motion.rel_x = rel_x; @@ -697,10 +530,11 @@ static int xenfb_send_motion(struct xenf return xenfb_kbd_event(xenfb, &event); } +/* Send an absolute mouse movement event */ static int xenfb_send_position(struct xenfb *xenfb, int abs_x, int abs_y) { union xenkbd_in_event event; - + LOGF("ABS %d %d\n", abs_x, abs_y); memset(&event, 0, XENKBD_IN_EVENT_SIZE); event.type = XENKBD_TYPE_POS; event.pos.abs_x = abs_x; @@ -753,161 +587,459 @@ static void xenfb_update(void *opaque) /* QEMU display state changed, so refresh the framebuffer copy */ static void xenfb_invalidate(void *opaque) { - struct xenfb *xenfb = (struct xenfb *)opaque; - xenfb_guest_copy(xenfb, 0, 0, xenfb->data.width, xenfb->data.height); + xenfb_update(opaque); } /* Screen dump is not used in Xen, so no need to impl this ? */ static void xenfb_screen_dump(void *opaque, const char *name) { } - +/* Process events from the frontend event channel */ static void xenfb_dispatch_channel(void *opaque) { struct xenfb *xenfb = (struct xenfb *)opaque; evtchn_port_t port; port = xc_evtchn_pending(xenfb->evt_xch); - if (port == -1) + if (port == -1) { + xenfb_shutdown(xenfb); exit(1); + } if (port == xenfb->fb.port) xenfb_on_fb_event(xenfb); else if (port == xenfb->kbd.port) xenfb_on_kbd_event(xenfb); - if (xc_evtchn_unmask(xenfb->evt_xch, port) == -1) + if (xc_evtchn_unmask(xenfb->evt_xch, port) == -1) { + xenfb_shutdown(xenfb); exit(1); -} - -static void xenfb_dispatch_store(void *opaque) -{ - struct xenfb *xenfb = (struct xenfb *)opaque; - unsigned dummy; - char **vec; - int r; - - vec = xs_read_watch(xenfb->xsh, &dummy); - free(vec); - r = xenfb_on_state_change(&xenfb->fb); - if (r == 0) - r = xenfb_on_state_change(&xenfb->kbd); - if (r == -1) - exit(1); -} - - -int xenfb_attach_dom(struct xenfb *xenfb, int domid, DisplayState *ds) -{ - struct xs_handle *xsh = xenfb->xsh; - int val, serrno; + } +} + + +/* Process ongoing events from the frontend devices */ +static void xenfb_frontend_disconnected_kbd(void *opaque) +{ + struct xenfb_device *dev = (struct xenfb_device *)opaque; + unsigned dummy; + char **vec; + int r; + vec = xs_read_watch(dev->xenfb->xsh, &dummy); + free(vec); + + r = xenfb_on_state_change(&dev->xenfb->kbd); + if (r >= 0) + r = xenfb_on_state_change(&dev->xenfb->fb); + + if (r < 0) { + xs_unwatch(dev->xenfb->xsh, dev->otherend, ""); + xenfb_shutdown(dev->xenfb); + } +} + + +/* Register a QEMU console & input handlers */ +static void xenfb_register_console(struct xenfb *xenfb) { + /* Register our keyboard & mouse handlers */ + qemu_add_kbd_event_handler(xenfb_put_keycode, xenfb); + qemu_add_mouse_event_handler(xenfb_mouse_event, xenfb, + xenfb->data.abs_pointer_wanted, + "Xen PVFB Mouse"); + + /* Tell QEMU to allocate a graphical console even though + * we''re not connected - so user at least has a black screen + * to look at ;-) */ + graphic_console_init(xenfb->ds, + xenfb_update, + xenfb_invalidate, + xenfb_screen_dump, + xenfb); + + LOGF("FB: Connected, resizing framebuffer\n"); + dpy_resize(xenfb->ds, xenfb->data.width, xenfb->data.height); +} + +/* Process the frontend framebuffer config */ +static int xenfb_read_frontend_fb_config(struct xenfb *xenfb) { struct xenfb_page *fb_page; - - xenfb_detach_dom(xenfb); - - xenfb_device_set_domain(&xenfb->fb, domid); - xenfb_device_set_domain(&xenfb->kbd, domid); - - if (xenfb_wait_for_backend_creation(&xenfb->fb) < 0) - goto error; - if (xenfb_wait_for_backend_creation(&xenfb->kbd) < 0) - goto error; - - if (xenfb_xs_printf(xsh, xenfb->kbd.nodename, "feature-abs-pointer", "1")) - goto error; - if (xenfb_switch_state(&xenfb->fb, XenbusStateInitWait)) - goto error; - if (xenfb_switch_state(&xenfb->kbd, XenbusStateInitWait)) - goto error; - - if (xenfb_hotplug(&xenfb->fb) < 0) - goto error; - if (xenfb_hotplug(&xenfb->kbd) < 0) - goto error; - - if (!xs_watch(xsh, xenfb->fb.otherend, "")) - goto error; - if (!xs_watch(xsh, xenfb->kbd.otherend, "")) - goto error; - - if (xenfb_wait_for_frontend_initialised(&xenfb->fb) < 0) - goto error; - if (xenfb_wait_for_frontend_initialised(&xenfb->kbd) < 0) - goto error; - - if (xenfb_bind(&xenfb->fb) < 0) - goto error; - if (xenfb_bind(&xenfb->kbd) < 0) - goto error; - - if (xenfb_xs_scanf1(xsh, xenfb->fb.otherend, "feature-update", - "%d", &val) < 0) - val = 0; - if (!val) { - errno = ENOTSUP; - goto error; - } - if (xenfb_xs_scanf1(xsh, xenfb->fb.otherend, "protocol", "%63s", - xenfb->protocol) < 0) - xenfb->protocol[0] = ''\0''; - xenfb_xs_printf(xsh, xenfb->fb.nodename, "request-update", "1"); - - /* TODO check for permitted ranges */ - fb_page = xenfb->fb.page; - xenfb->data.depth = fb_page->depth; - xenfb->data.width = fb_page->width; - xenfb->data.height = fb_page->height; - /* TODO check for consistency with the above */ - xenfb->data.len = fb_page->mem_length; - xenfb->data.row_stride = fb_page->line_length; - - if (xenfb_map_fb(xenfb, domid) < 0) - goto error; - - if (xenfb_switch_state(&xenfb->fb, XenbusStateConnected)) - goto error; - if (xenfb_switch_state(&xenfb->kbd, XenbusStateConnected)) - goto error; - - if (xenfb_wait_for_frontend_connected(&xenfb->kbd) < 0) - goto error; - if (xenfb_xs_scanf1(xsh, xenfb->kbd.otherend, "request-abs-pointer", + int val; + + if (xenfb_xs_scanf1(xenfb->xsh, xenfb->fb.otherend, "feature-update", + "%d", &val) < 0) + val = 0; + if (!val) { + LOGF("feature-update not supported\n"); + errno = ENOTSUP; + return -1; + } + if (xenfb_xs_scanf1(xenfb->xsh, xenfb->fb.otherend, "protocol", "%63s", + xenfb->protocol) < 0) + xenfb->protocol[0] = ''\0''; + xenfb_xs_printf(xenfb->xsh, xenfb->fb.nodename, "request-update", "1"); + + /* TODO check for permitted ranges */ + fb_page = xenfb->fb.page; + xenfb->data.depth = fb_page->depth; + xenfb->data.width = fb_page->width; + xenfb->data.height = fb_page->height; + /* TODO check for consistency with the above */ + xenfb->data.len = fb_page->mem_length; + xenfb->data.row_stride = fb_page->line_length; + LOGF("Framebuffer depth %d width %d height %d line %d\n", + fb_page->depth, fb_page->width, fb_page->height, fb_page->line_length); + if (xenfb_map_fb(xenfb, xenfb->fb.otherend_id) < 0) + return -1; + + if (xenfb_switch_state(&xenfb->fb, XenbusStateConnected)) + return -1; + if (xenfb_switch_state(&xenfb->kbd, XenbusStateConnected)) + return -1; + + return 0; +} + +/* Process the frontend keyboard config */ +static int xenfb_read_frontend_kbd_config(struct xenfb *xenfb) +{ + int val; + + if (xenfb_xs_scanf1(xenfb->xsh, xenfb->kbd.otherend, "request-abs-pointer", "%d", &val) < 0) val = 0; xenfb->data.abs_pointer_wanted = val; - /* Listen for events from xenstore */ - if (qemu_set_fd_handler2(xs_fileno(xenfb->xsh), NULL, xenfb_dispatch_store, NULL, xenfb) < 0) - goto error; - - /* Listen for events from the event channel */ - if (qemu_set_fd_handler2(xc_evtchn_fd(xenfb->evt_xch), NULL, xenfb_dispatch_channel, NULL, xenfb) < 0) - goto error; - - /* Register our keyboard & mouse handlers */ - qemu_add_kbd_event_handler(xenfb_put_keycode, xenfb); - qemu_add_mouse_event_handler(xenfb_mouse_event, xenfb, - xenfb->data.abs_pointer_wanted, - "Xen PVFB Mouse"); - + return 0; +} + +/* Register a watch against a frontend device, and setup + * QEMU event loop to poll the xenstore FD for notification */ +static int xenfb_wait_for_frontend(struct xenfb_device *dev, IOHandler *handler) +{ + LOGF("Doing frontend watch on %s\n", dev->otherend); + if (!xs_watch(dev->xenfb->xsh, dev->otherend, "")) { + LOGF("Watch for dev failed\n"); + return -1; + } + + if (qemu_set_fd_handler2(xs_fileno(dev->xenfb->xsh), NULL, handler, NULL, dev) < 0) + return -1; + + return 0; +} + +/* Register a watch against a backend device, and setup + * QEMU event loop to poll the xenstore FD for notification */ +static int xenfb_wait_for_backend(struct xenfb_device *dev, IOHandler *handler) +{ + LOGF("Doing backend watch on %s\n", dev->nodename); + if (!xs_watch(dev->xenfb->xsh, dev->nodename, "")) { + LOGF("Watch for dev failed\n"); + return -1; + } + + if (qemu_set_fd_handler2(xs_fileno(dev->xenfb->xsh), NULL, handler, NULL, dev) < 0) + return -1; + + return 0; +} + + +/* Helper to determine if a frontend device is in Connected state */ +static int xenfb_frontend_connected(struct xenfb_device *dev) +{ + unsigned int state; + unsigned int dummy; + char **vec; + vec = xs_read_watch(dev->xenfb->xsh, &dummy); + if (!vec) { + xs_unwatch(dev->xenfb->xsh, dev->otherend, ""); + return -1; + } + free(vec); + + state = xenfb_read_state(dev->xenfb->xsh, dev->otherend); + if (!((1 <<state) & ((1 << XenbusStateUnknown) | + (1 << XenbusStateConnected)))) { + LOGF("FB: Carry on waiting\n"); + return 1; + } + + xs_unwatch(dev->xenfb->xsh, dev->otherend, ""); + + switch (state) { + case XenbusStateConnected: + break; + default: + return -1; + } + return 0; +} + + +/* Helper to determine if a frontend device is in Initialized state */ +static int xenfb_frontend_initialized(struct xenfb_device *dev) +{ + unsigned int state; + unsigned int dummy; + char **vec; + vec = xs_read_watch(dev->xenfb->xsh, &dummy); + if (!vec) { + xs_unwatch(dev->xenfb->xsh, dev->otherend, ""); + return -1; + } + free(vec); + + state = xenfb_read_state(dev->xenfb->xsh, dev->otherend); + + if (!((1 << state) & ((1 << XenbusStateUnknown) + | (1 << XenbusStateInitialised) +#if 1 /* TODO fudging state to permit restarting; to be removed */ + | (1 << XenbusStateConnected) +#endif + ))) { + LOGF("FB: Carry on waiting\n"); + return 1; + } + + xs_unwatch(dev->xenfb->xsh, dev->otherend, ""); + + switch (state) { +#if 1 + case XenbusStateConnected: + LOGF("Fudging state to %d\n", XenbusStateInitialised); /* FIXME */ +#endif + case XenbusStateInitialised: + break; + default: + return -1; + } + + if (xenfb_bind(dev) < 0) + return -1; + + return 0; +} + +/* Helper to determine if a backend device is in Created state */ +int xenfb_backend_created(struct xenfb_device *dev) +{ + unsigned int state; + unsigned int dummy; + char **vec; + vec = xs_read_watch(dev->xenfb->xsh, &dummy); + if (!vec) { + xs_unwatch(dev->xenfb->xsh, dev->nodename, ""); + return -1; + } + free(vec); + + state = xenfb_read_state(dev->xenfb->xsh, dev->nodename); + + if (!((1 <<state) & ((1 << XenbusStateUnknown) + | (1 << XenbusStateInitialising) + | (1 << XenbusStateClosed) +#if 1 /* TODO fudging state to permit restarting; to be removed */ + | (1 << XenbusStateInitWait) + | (1 << XenbusStateConnected) + | (1 << XenbusStateClosing) +#endif + ))) { + LOGF("FB: Carry on waiting\n"); + return 1; + } + + xs_unwatch(dev->xenfb->xsh, dev->nodename, ""); + + switch (state) { +#if 1 + case XenbusStateInitWait: + case XenbusStateConnected: + LOGF("FB: Fudging state to %d\n", XenbusStateInitialising); /* FIXME */ +#endif + case XenbusStateInitialising: + case XenbusStateClosing: + case XenbusStateClosed: + break; + default: + LOGF("FB: Wrong state %d\n", state); + return -1; + } + xenfb_switch_state(dev, XenbusStateInitWait); + if (xenfb_hotplug(dev) < 0) + return -1; + + return 0; +} + +/* Callback invoked while waiting for KBD frontend to change + * to the connected state */ +void xenfb_frontend_connected_kbd(void *opaque) +{ + struct xenfb_device *dev = (struct xenfb_device *)opaque; + int ret = xenfb_frontend_connected(dev); + if (ret < 0) { + xenfb_shutdown(dev->xenfb); + return; + } + if (ret) + return; /* Still waiting */ + + if (xenfb_read_frontend_kbd_config(dev->xenfb) < 0) { + xenfb_shutdown(dev->xenfb); + return; + } + + xenfb_register_console(dev->xenfb); + + if (qemu_set_fd_handler2(dev->xenfb->evt_xch, NULL, xenfb_dispatch_channel, NULL, dev->xenfb) < 0) { + xenfb_shutdown(dev->xenfb); + return; + } + + LOGF("FB: Waiting for KBD frontend disconnection\n"); + xenfb_wait_for_frontend(&dev->xenfb->kbd, xenfb_frontend_disconnected_kbd); +} + +/* Callback invoked while waiting for FB frontend to change + * to the initialized state */ +void xenfb_frontend_initialized_fb(void *opaque) +{ + struct xenfb_device *dev = (struct xenfb_device *)opaque; + int ret = xenfb_frontend_initialized(dev); + if (ret < 0) { + xenfb_shutdown(dev->xenfb); + return; + } + if (ret) + return; /* Still waiting */ + + + if (xenfb_read_frontend_fb_config(dev->xenfb)) { + xenfb_shutdown(dev->xenfb); + return; + } + + LOGF("FB: Waiting for KBD frontend connection\n"); + xenfb_wait_for_frontend(&dev->xenfb->kbd, xenfb_frontend_connected_kbd); +} + +/* Callback invoked while waiting for KBD frontend to change + * to the initialized state */ +void xenfb_frontend_initialized_kbd(void *opaque) +{ + struct xenfb_device *dev = (struct xenfb_device *)opaque; + int ret = xenfb_frontend_initialized(dev); + if (ret < 0) { + xenfb_shutdown(dev->xenfb); + return; + } + if (ret) + return; /* Still waiting */ + + + LOGF("FB: Waiting for FB frontend initialization\n"); + xenfb_wait_for_frontend(&dev->xenfb->fb, xenfb_frontend_initialized_fb); +} + +/* Callback invoked while waiting for FB backend to change + * to the created state */ +void xenfb_backend_created_fb(void *opaque) +{ + struct xenfb_device *dev = (struct xenfb_device *)opaque; + int ret = xenfb_backend_created(dev); + if (ret < 0) { + xenfb_shutdown(dev->xenfb); + return; + } + if (ret) + return; /* Still waiting */ + + LOGF("FB: Waiting for KBD frontend initialization\n"); + xenfb_wait_for_frontend(&dev->xenfb->kbd, xenfb_frontend_initialized_kbd); +} + +/* Callback invoked while waiting for KBD backend to change + * to the created state */ +void xenfb_backend_created_kbd(void *opaque) +{ + struct xenfb_device *dev = (struct xenfb_device *)opaque; + int ret = xenfb_backend_created(dev); + if (ret < 0) { + xenfb_shutdown(dev->xenfb); + return; + } + if (ret) + return; /* Still waiting */ + + if (xenfb_xs_printf(dev->xenfb->xsh, dev->nodename, "feature-abs-pointer", "1")) { + xenfb_shutdown(dev->xenfb); + return; + } + + LOGF("FB: Waiting for FB backend creation\n"); + xenfb_wait_for_backend(&dev->xenfb->fb, xenfb_backend_created_fb); +} + + +/* Create a new Xen FB associated with QEMU DisplayState, + * wait for domid to appear and connect to its frontend */ +struct xenfb *xenfb_new(int domid, DisplayState *ds) +{ + int serrno; + struct xenfb *xenfb = qemu_malloc(sizeof(struct xenfb)); + + if (xenfb == NULL) + return NULL; + + memset(xenfb, 0, sizeof(*xenfb)); xenfb->ds = ds; - - /* Tell QEMU to allocate a graphical console */ - graphic_console_init(ds, - xenfb_update, - xenfb_invalidate, - xenfb_screen_dump, - xenfb); - dpy_resize(ds, xenfb->data.width, xenfb->data.height); - - return 0; - - error: - serrno = errno; - xenfb_detach_dom(xenfb); - xenfb_dev_fatal(&xenfb->fb, serrno, "on fire"); - xenfb_dev_fatal(&xenfb->kbd, serrno, "on fire"); - errno = serrno; - return -1; + xenfb->evt_xch = xenfb->xc = -1; + xenfb_device_init(&xenfb->fb, "vfb", xenfb); + xenfb_device_init(&xenfb->kbd, "vkbd", xenfb); + + xenfb->evt_xch = xc_evtchn_open(); + if (xenfb->evt_xch == -1) + goto fail; + + xenfb->xc = xc_interface_open(); + if (xenfb->xc == -1) + goto fail; + + xenfb->xsh = xs_daemon_open(); + if (!xenfb->xsh) + goto fail; + + xenfb_device_set_domain(&xenfb->fb, domid); + xenfb_device_set_domain(&xenfb->kbd, domid); + + LOGF("FB: Waiting for KBD backend creation\n"); + xenfb_wait_for_backend(&xenfb->kbd, xenfb_backend_created_kbd); + + return xenfb; + + fail: + serrno = errno; + xenfb_shutdown(xenfb); + errno = serrno; + return NULL; +} + +/* Remove the backend area in xenbus since the framebuffer really is + going away. */ +void xenfb_shutdown(struct xenfb *xenfb) +{ + LOGF("FB: Shutting down backend\n"); + xs_rm(xenfb->xsh, XBT_NULL, xenfb->fb.nodename); + xs_rm(xenfb->xsh, XBT_NULL, xenfb->kbd.nodename); + + xenfb_detach_dom(xenfb); + if (xenfb->xc >= 0) + xc_interface_close(xenfb->xc); + if (xenfb->evt_xch >= 0) + xc_evtchn_close(xenfb->evt_xch); + if (xenfb->xsh) + xs_daemon_close(xenfb->xsh); + free(xenfb); } /* diff -r 829464d36542 tools/ioemu/hw/xenfb.h --- a/tools/ioemu/hw/xenfb.h Tue Aug 21 22:07:47 2007 -0400 +++ b/tools/ioemu/hw/xenfb.h Tue Aug 21 22:08:24 2007 -0400 @@ -7,10 +7,7 @@ struct xenfb; -struct xenfb *xenfb_new(void); -void xenfb_delete(struct xenfb *xenfb); -void xenfb_teardown(struct xenfb *xenfb); - -int xenfb_attach_dom(struct xenfb *xenfb, int domid, DisplayState *ds); +struct xenfb *xenfb_new(int domid, DisplayState *ds); +void xenfb_shutdown(struct xenfb *xenfb); #endif -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=| _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel P. Berrange
2007-Aug-22 22:32 UTC
Re: [Xen-devel] PATCH: 8/10: Add pv console to QEMU paravirt machine
This patch adds a paravirt console driver to qemu-dm. This is used when the QEMU machine type is ''xenpv'', connecting to the ring buffer provided by the guest kernel. The ''-serial'' command line flag controls how the guest console is exposed. For parity with xenconsoled the ''-serial pty'' arg can be used. For guests which are running a qemu-dm device model, the xenconsoled daemon is no longer needed for guest consoles. The code for the xen_console.c is based on the original code in tools/console/daemon/io.c, but simplified; since its only dealing with a single guest there''s no state tracking to worry about. b/tools/ioemu/hw/xen_console.c | 424 ++++++++++++++++++++++++++++++++++++++++ b/tools/ioemu/hw/xen_console.h | 25 ++ tools/ioemu/Makefile.target | 1 tools/ioemu/hw/xen_machine_pv.c | 9 tools/ioemu/xenstore.c | 2 5 files changed, 460 insertions(+), 1 deletion(-) Signed-off-by: Daniel P. Berrange <berrange@redhat.com> Dan. diff -r fb720737dddb tools/ioemu/Makefile.target --- a/tools/ioemu/Makefile.target Tue Aug 21 22:15:30 2007 -0400 +++ b/tools/ioemu/Makefile.target Tue Aug 21 22:16:00 2007 -0400 @@ -403,6 +403,7 @@ VL_OBJS+= xen_machine_fv.o VL_OBJS+= xen_machine_fv.o VL_OBJS+= xen_machine_pv.o VL_OBJS+= xenfb.o +VL_OBJS+= xen_console.o VL_OBJS+= tpm_tis.o CPPFLAGS += -DHAS_AUDIO endif diff -r fb720737dddb tools/ioemu/hw/xen_console.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/ioemu/hw/xen_console.c Tue Aug 21 22:16:00 2007 -0400 @@ -0,0 +1,424 @@ +/* + * Copyright (C) International Business Machines Corp., 2005 + * Author(s): Anthony Liguori <aliguori@us.ibm.com> + * + * Copyright (C) Red Hat 2007 + * + * Xen Console + * + * 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; under version 2 of the License. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <xs.h> +#include <xen/io/console.h> +#include <xenctrl.h> + +#include <malloc.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <sys/select.h> +#include <fcntl.h> +#include <unistd.h> +#include <termios.h> +#include <stdarg.h> +#include <sys/mman.h> +#include "vl.h" + +#include "xen_console.h" + +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +/* Each 10 bits takes ~ 3 digits, plus one, plus one for nul terminator. */ +#define MAX_STRLEN(x) ((sizeof(x) * CHAR_BIT + CHAR_BIT-1) / 10 * 3 + 2) + +#define dolog(val, fmt, ...) fprintf(stderr, fmt "\n", ## __VA_ARGS__) + +struct buffer +{ + uint8_t *data; + size_t consumed; + size_t size; + size_t capacity; + size_t max_capacity; +}; + +struct domain +{ + int domid; + struct buffer buffer; + + char *conspath; + char *serialpath; + int use_consolepath; + int ring_ref; + evtchn_port_t local_port; + evtchn_port_t remote_port; + int xce_handle; + struct xs_handle *xsh; + struct xencons_interface *interface; + CharDriverState *chr; +}; + + +static void buffer_append(struct domain *dom) +{ + struct buffer *buffer = &dom->buffer; + XENCONS_RING_IDX cons, prod, size; + struct xencons_interface *intf = dom->interface; + + cons = intf->out_cons; + prod = intf->out_prod; + mb(); + + size = prod - cons; + if ((size == 0) || (size > sizeof(intf->out))) + return; + + if ((buffer->capacity - buffer->size) < size) { + buffer->capacity += (size + 1024); + buffer->data = realloc(buffer->data, buffer->capacity); + if (buffer->data == NULL) { + dolog(LOG_ERR, "Memory allocation failed"); + exit(ENOMEM); + } + } + + while (cons != prod) + buffer->data[buffer->size++] = intf->out[ + MASK_XENCONS_IDX(cons++, intf->out)]; + + mb(); + intf->out_cons = cons; + xc_evtchn_notify(dom->xce_handle, dom->local_port); + + if (buffer->max_capacity && + buffer->size > buffer->max_capacity) { + /* Discard the middle of the data. */ + + size_t over = buffer->size - buffer->max_capacity; + uint8_t *maxpos = buffer->data + buffer->max_capacity; + + memmove(maxpos - over, maxpos, over); + buffer->data = realloc(buffer->data, buffer->max_capacity); + buffer->size = buffer->capacity = buffer->max_capacity; + + if (buffer->consumed > buffer->max_capacity - over) + buffer->consumed = buffer->max_capacity - over; + } +} + +static void buffer_advance(struct buffer *buffer, size_t len) +{ + buffer->consumed += len; + if (buffer->consumed == buffer->size) { + buffer->consumed = 0; + buffer->size = 0; + } +} + +/* Takes tuples of names, scanf-style args, and void **, NULL terminated. */ +int xs_gather(struct xs_handle *xs, const char *dir, ...) +{ + va_list ap; + const char *name; + char *path; + int ret = 0; + + va_start(ap, dir); + while (ret == 0 && (name = va_arg(ap, char *)) != NULL) { + const char *fmt = va_arg(ap, char *); + void *result = va_arg(ap, void *); + char *p; + + if (asprintf(&path, "%s/%s", dir, name) == -1) { + ret = ENOMEM; + break; + } + p = xs_read(xs, XBT_NULL, path, NULL); + free(path); + if (p == NULL) { + ret = ENOENT; + break; + } + if (fmt) { + if (sscanf(p, fmt, result) == 0) + ret = EINVAL; + free(p); + } else + *(char **)result = p; + } + va_end(ap); + return ret; +} + +static int domain_create_ring(struct domain *dom) +{ + int err, remote_port, ring_ref, rc; + + err = xs_gather(dom->xsh, dom->serialpath, + "ring-ref", "%u", &ring_ref, + "port", "%i", &remote_port, + NULL); + if (err) { + err = xs_gather(dom->xsh, dom->conspath, + "ring-ref", "%u", &ring_ref, + "port", "%i", &remote_port, + NULL); + if (err) { + fprintf(stderr, "Console: failed to find ring-ref/port yet\n"); + goto out; + } + dom->use_consolepath = 1; + } else + dom->use_consolepath = 0; + fprintf(stderr, "Console: got ring-ref %d port %d\n", ring_ref, remote_port); + + if ((ring_ref == dom->ring_ref) && (remote_port == dom->remote_port)) + goto out; + + if (ring_ref != dom->ring_ref) { + if (dom->interface != NULL) + munmap(dom->interface, getpagesize()); + dom->interface = xc_map_foreign_range( + xc_handle, dom->domid, getpagesize(), + PROT_READ|PROT_WRITE, + (unsigned long)ring_ref); + if (dom->interface == NULL) { + err = -errno; + goto out; + } + dom->ring_ref = ring_ref; + } + + dom->local_port = -1; + dom->remote_port = -1; + + dom->xce_handle = xc_evtchn_open(); + if (dom->xce_handle == -1) { + err = -errno; + goto out; + } + + rc = xc_evtchn_bind_interdomain(dom->xce_handle, + dom->domid, remote_port); + + if (rc == -1) { + err = -errno; + xc_evtchn_close(dom->xce_handle); + dom->xce_handle = -1; + goto out; + } + dom->local_port = rc; + dom->remote_port = remote_port; + + out: + return err; +} + + +static struct domain *create_domain(int domid, CharDriverState *chr) +{ + struct domain *dom; + char *s; + + dom = (struct domain *)malloc(sizeof(struct domain)); + if (dom == NULL) { + dolog(LOG_ERR, "Out of memory %s:%s():L%d", + __FILE__, __FUNCTION__, __LINE__); + exit(ENOMEM); + } + + dom->domid = domid; + dom->chr = chr; + + dom->xsh = xs_daemon_open(); + if (dom->xsh == NULL) { + fprintf(logfile, "Could not contact xenstore for console watch\n"); + goto out; + } + + dom->serialpath = xs_get_domain_path(dom->xsh, dom->domid); + s = realloc(dom->serialpath, strlen(dom->serialpath) + + strlen("/serial/0") + 1); + if (s == NULL) + goto out; + dom->serialpath = s; + strcat(dom->serialpath, "/serial/0"); + + dom->conspath = xs_get_domain_path(dom->xsh, dom->domid); + s = realloc(dom->conspath, strlen(dom->conspath) + + strlen("/console") + 1); + if (s == NULL) + goto out; + dom->conspath = s; + strcat(dom->conspath, "/console"); + + dom->buffer.data = 0; + dom->buffer.consumed = 0; + dom->buffer.size = 0; + dom->buffer.capacity = 0; + dom->buffer.max_capacity = 0; + + dom->ring_ref = -1; + dom->local_port = -1; + dom->remote_port = -1; + dom->interface = NULL; + dom->xce_handle = -1; + + + return dom; + out: + free(dom->serialpath); + free(dom->conspath); + free(dom); + return NULL; +} + + +static int ring_free_bytes(struct domain *dom) +{ + struct xencons_interface *intf = dom->interface; + XENCONS_RING_IDX cons, prod, space; + + cons = intf->in_cons; + prod = intf->in_prod; + mb(); + + space = prod - cons; + if (space > sizeof(intf->in)) + return 0; /* ring is screwed: ignore it */ + + return (sizeof(intf->in) - space); +} + +static int xencons_can_receive(void *opaque) +{ + struct domain *dom = (struct domain *)opaque; + + return ring_free_bytes(dom); +} + +static void xencons_receive(void *opaque, const uint8_t *buf, int len) +{ + struct domain *dom = (struct domain *)opaque; + int i, max; + struct xencons_interface *intf = dom->interface; + XENCONS_RING_IDX prod; + + max = ring_free_bytes(dom); + /* The can_receive() func limits this, but check again anyway */ + if (max < len) + len = max; + + prod = intf->in_prod; + for (i = 0; i < len; i++) { + intf->in[MASK_XENCONS_IDX(prod++, intf->in)] + buf[i]; + } + wmb(); + intf->in_prod = prod; + xc_evtchn_notify(dom->xce_handle, dom->local_port); +} + +static void xencons_send(struct domain *dom) +{ + ssize_t len; + len = qemu_chr_write(dom->chr, dom->buffer.data + dom->buffer.consumed, + dom->buffer.size - dom->buffer.consumed); + if (len < 1) { + /* + * Disable log because if we''re redirecting to /dev/pts/N we + * don''t want to flood logs when no client has the PTY open + */ + /* + dolog(LOG_DEBUG, "Write failed on domain %d: %zd, %d\n", + dom->domid, len, errno); + */ + } else { + buffer_advance(&dom->buffer, len); + } +} + +static void xencons_ring_read(void *opaque) +{ + evtchn_port_t port; + struct domain *dom = (struct domain *)opaque; + + if ((port = xc_evtchn_pending(dom->xce_handle)) == -1) + return; + + buffer_append(dom); + + (void)xc_evtchn_unmask(dom->xce_handle, port); + + if (dom->buffer.size - dom->buffer.consumed) + xencons_send(dom); +} + +static void xencons_startup(void *opaque) +{ + struct domain *dom = (struct domain *)opaque; + unsigned dummy; + char **vec; + int err; + vec = xs_read_watch(dom->xsh, &dummy); + if (vec) + free(vec); + fprintf(stderr, "Console: got watch\n"); + err = domain_create_ring(dom); + if (err) + return; + + xs_unwatch(dom->xsh, dom->conspath, ""); + xs_unwatch(dom->xsh, dom->serialpath, ""); + qemu_set_fd_handler2(xs_fileno(dom->xsh), NULL, NULL, NULL, NULL); + + fprintf(stderr, "Console: connected to guest frontend\n"); + if (qemu_set_fd_handler2(dom->xce_handle, NULL, xencons_ring_read, NULL, dom) < 0) + return; + + qemu_chr_add_handlers(dom->chr, xencons_can_receive, xencons_receive, + NULL, dom); +} + + +int xencons_init(int domid, CharDriverState *chr) +{ + struct domain *dom = create_domain(domid, chr); + + if (!dom) + return -1; + + /* Setup watches so we asynchronously connect to serial console */ + xs_watch(dom->xsh, dom->conspath, ""); + xs_watch(dom->xsh, dom->serialpath, ""); + qemu_set_fd_handler2(xs_fileno(dom->xsh), NULL, xencons_startup, NULL, dom); + fprintf(stderr, "Console: prepared domain, waiting for ringref at %s or %s\n", + dom->conspath, dom->serialpath); + + return 0; +} + + +/* + * Local variables: + * c-file-style: "linux" + * indent-tabs-mode: t + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff -r fb720737dddb tools/ioemu/hw/xen_console.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/ioemu/hw/xen_console.h Tue Aug 21 22:16:00 2007 -0400 @@ -0,0 +1,25 @@ +/* + * Copyright (C) International Business Machines Corp., 2005 + * Author(s): Anthony Liguori <aliguori@us.ibm.com> + * + * Copyright (C) Red Hat 2007 + * + * Xen Console + * + * 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; under version 2 of the License. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "vl.h" + +extern int xencons_init(int domid, CharDriverState *chr); diff -r fb720737dddb tools/ioemu/hw/xen_machine_pv.c --- a/tools/ioemu/hw/xen_machine_pv.c Tue Aug 21 22:15:30 2007 -0400 +++ b/tools/ioemu/hw/xen_machine_pv.c Tue Aug 21 22:16:00 2007 -0400 @@ -23,6 +23,7 @@ */ #include "vl.h" +#include "xen_console.h" #include "xenfb.h" @@ -39,6 +40,14 @@ static void xen_init_pv(uint64_t ram_siz { struct xenfb *xenfb; extern int domid; + + /* Connect to text console */ + if (serial_hds[0]) { + if (xencons_init(domid, serial_hds[0]) < 0) { + fprintf(stderr, "Could not connect to domain console\n"); + exit(1); + } + } /* Prepare PVFB state */ xenfb = xenfb_new(domid, ds); diff -r fb720737dddb tools/ioemu/xenstore.c --- a/tools/ioemu/xenstore.c Tue Aug 21 22:15:30 2007 -0400 +++ b/tools/ioemu/xenstore.c Tue Aug 21 22:16:00 2007 -0400 @@ -17,7 +17,7 @@ #include <sys/stat.h> #include <fcntl.h> -static struct xs_handle *xsh = NULL; +struct xs_handle *xsh = NULL; static char *media_filename[MAX_DISKS + MAX_SCSI_DISKS]; static QEMUTimer *insert_timer = NULL; -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=| _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel P. Berrange
2007-Aug-22 22:33 UTC
Re: [Xen-devel] PATCH: 9/10: XenD device model re-factoring
This patches adapts XenD so that it is capable of starting a qemu-dm device model for both paravirt and fullyvirt guests. A paravirt guest will only be given a device model if it has a VFB configured, or the user explicitly include the device_model option in the config config. This avoids unneccessary overhead for those wanting a minimal paravirt guest. The bulk of this patch involves moving code from the HVMImageHandler into the base ImageHandler class. The HVMImageHandler and LinuxImageHandler subclasses now merely containing a couple of overrides to set some specific command line flags. The most important is -M xenpv, vs -M xenfv. The XenConfig class has a minor refactoring to add a has_rfb() method to avoid duplicating code in a couple of places. Instead of hardcoding DEFAULT_DM it now uses the xen.util.auxbin APIs to locate it - this works on platforms where qemu-dm is in /usr/lib64 instead of /usr/lib. As before paravirt only gets a default qemu-dm if using a VFB The vfbif.py class is trimmed out since it no longer needs to spawn a daemon. A few other misc fixes deal with qemu-dm interactions when saving/restoring, and in particular recovering from save failures (or checkpointing). XendCheckpoint.py | 5 XendConfig.py | 35 ++-- XendDomainInfo.py | 34 ++-- image.py | 379 ++++++++++++++++++++++++++++-------------------------- server/vfbif.py | 110 ++------------- 5 files changed, 254 insertions(+), 309 deletions(-) Signed-off-by: Daniel P. Berrange <berrange@redhat.com> Dan. diff -r 912986c9283d tools/python/xen/xend/XendCheckpoint.py --- a/tools/python/xen/xend/XendCheckpoint.py Wed Aug 22 16:17:45 2007 -0400 +++ b/tools/python/xen/xend/XendCheckpoint.py Wed Aug 22 16:17:49 2007 -0400 @@ -6,6 +6,7 @@ # this archive for more details. import os +import os.path import re import string import threading @@ -105,7 +106,7 @@ def save(fd, dominfo, network, live, dst forkHelper(cmd, fd, saveInputHandler, False) # put qemu device model state - if hvm: + if os.path.exists("/var/lib/xen/qemu-save.%d" % dominfo.getDomid()): write_exact(fd, QEMU_SIGNATURE, "could not write qemu signature") qemu_fd = os.open("/var/lib/xen/qemu-save.%d" % dominfo.getDomid(), os.O_RDONLY) @@ -231,6 +232,8 @@ def restore(xd, fd, dominfo = None, paus raise XendError(''Could not read console MFN'') # get qemu state and create a tmp file for dm restore + # Even PV guests may have QEMU stat, but its not currently + # used so only bother with HVM currently. if is_hvm: qemu_signature = read_exact(fd, len(QEMU_SIGNATURE), "invalid device model signature read") diff -r 912986c9283d tools/python/xen/xend/XendConfig.py --- a/tools/python/xen/xend/XendConfig.py Wed Aug 22 16:17:45 2007 -0400 +++ b/tools/python/xen/xend/XendConfig.py Wed Aug 22 16:17:49 2007 -0400 @@ -32,6 +32,7 @@ from xen.util.blkif import blkdev_name_t from xen.util.blkif import blkdev_name_to_number from xen.xend.XendXSPolicyAdmin import XSPolicyAdminInstance from xen.util import xsconstants +import xen.util.auxbin log = logging.getLogger("xend.XendConfig") log.setLevel(logging.WARN) @@ -236,8 +237,6 @@ LEGACY_XENSTORE_VM_PARAMS = [ ''on_xend_start'', ''on_xend_stop'', ] - -DEFAULT_DM = ''/usr/lib/xen/bin/qemu-dm'' ## ## Config Choices @@ -398,13 +397,14 @@ class XendConfig(dict): self[''name_label''] = ''Domain-'' + self[''uuid''] def _platform_sanity_check(self): + if ''keymap'' not in self[''platform''] and XendOptions.instance().get_keymap(): + self[''platform''][''keymap''] = XendOptions.instance().get_keymap() + + if self.is_hvm() or self.has_rfb(): + if ''device_model'' not in self[''platform'']: + self[''platform''][''device_model''] = xen.util.auxbin.pathTo("qemu-dm") + if self.is_hvm(): - if ''keymap'' not in self[''platform''] and XendOptions.instance().get_keymap(): - self[''platform''][''keymap''] = XendOptions.instance().get_keymap() - - if ''device_model'' not in self[''platform'']: - self[''platform''][''device_model''] = DEFAULT_DM - # Compatibility hack, can go away soon. if ''soundhw'' not in self[''platform''] and \ self[''platform''].get(''enable_audio''): @@ -740,16 +740,7 @@ class XendConfig(dict): # coalesce hvm vnc frame buffer with vfb config if self.is_hvm() and int(self[''platform''].get(''vnc'', 0)) != 0: # add vfb device if it isn''t there already - has_rfb = False - for console_uuid in self[''console_refs'']: - if self[''devices''][console_uuid][1].get(''protocol'') == ''rfb'': - has_rfb = True - break - if self[''devices''][console_uuid][0] == ''vfb'': - has_rfb = True - break - - if not has_rfb: + if not self.has_rfb(): dev_config = [''vfb''] # copy VNC related params from platform config to vfb dev conf for key in [''vncpasswd'', ''vncunused'', ''vncdisplay'', @@ -759,6 +750,14 @@ class XendConfig(dict): self.device_add(''vfb'', cfg_sxp = dev_config) + + def has_rfb(self): + for console_uuid in self[''console_refs'']: + if self[''devices''][console_uuid][1].get(''protocol'') == ''rfb'': + return True + if self[''devices''][console_uuid][0] == ''vfb'': + return True + return False def _sxp_to_xapi_unsupported(self, sxp_cfg): """Read in an SXP configuration object and populate diff -r 912986c9283d tools/python/xen/xend/XendDomainInfo.py --- a/tools/python/xen/xend/XendDomainInfo.py Wed Aug 22 16:17:45 2007 -0400 +++ b/tools/python/xen/xend/XendDomainInfo.py Wed Aug 22 16:20:05 2007 -0400 @@ -1347,10 +1347,16 @@ class XendDomainInfo: def _releaseDevices(self, suspend = False): """Release all domain''s devices. Nothrow guarantee.""" - if suspend and self.image: - self.image.destroy(suspend) - return - + if self.image: + try: + log.debug("Destroying device model") + self.image.destroyDeviceModel() + except Exception, e: + log.exception("Device model destroy failed %s" % str(e)) + else: + log.debug("No device model") + + log.debug("Releasing devices") t = xstransact("%s/device" % self.dompath) for devclass in XendDevices.valid_devices(): for dev in t.list(devclass): @@ -1360,8 +1366,8 @@ class XendDomainInfo: except: # Log and swallow any exceptions in removal -- # there''s nothing more we can do. - log.exception("Device release failed: %s; %s; %s", - self.info[''name_label''], devclass, dev) + log.exception("Device release failed: %s; %s; %s", + self.info[''name_label''], devclass, dev) @@ -1586,11 +1592,6 @@ class XendDomainInfo: bootloader_tidy(self) if self.image: - try: - self.image.destroy() - except: - log.exception( - "XendDomainInfo.cleanup: image.destroy() failed.") self.image = None try: @@ -1638,10 +1639,9 @@ class XendDomainInfo: self.console_mfn = console_mfn self._introduceDomain() - if self.info.is_hvm(): - self.image = image.create(self, self.info) - if self.image: - self.image.createDeviceModel(True) + self.image = image.create(self, self.info) + if self.image: + self.image.createDeviceModel(True) self._storeDomDetails() self._registerWatches() self.refreshShutdown() @@ -1758,8 +1758,8 @@ class XendDomainInfo: ResumeDomain(self.domid) except: log.exception("XendDomainInfo.resume: xc.domain_resume failed on domain %s." % (str(self.domid))) - if self.is_hvm(): - self.image.resumeDeviceModel() + self.image.resumeDeviceModel() + log.debug("XendDomainInfo.resumeDomain: completed") # diff -r 912986c9283d tools/python/xen/xend/image.py --- a/tools/python/xen/xend/image.py Wed Aug 22 16:17:45 2007 -0400 +++ b/tools/python/xen/xend/image.py Wed Aug 22 16:17:49 2007 -0400 @@ -56,10 +56,9 @@ class ImageHandler: defining in a subclass. The method createDeviceModel() is called to create the domain device - model if it needs one. The default is to do nothing. - - The method destroy() is called when the domain is destroyed. - The default is to do nothing. + model. + + The method destroyDeviceModel() is called to reap the device model """ ostype = None @@ -91,6 +90,15 @@ class ImageHandler: ("image/cmdline", self.cmdline), ("image/ramdisk", self.ramdisk)) + self.dmargs = self.parseDeviceModelArgs(vmConfig) + self.device_model = vmConfig[''platform''].get(''device_model'') + + self.display = vmConfig[''platform''].get(''display'') + self.xauthority = vmConfig[''platform''].get(''xauthority'') + self.vncconsole = vmConfig[''platform''].get(''vncconsole'') + self.pid = None + + def cleanupBootloading(self): if self.bootloader: @@ -173,25 +181,145 @@ class ImageHandler: """Build the domain. Define in subclass.""" raise NotImplementedError() + # Return a list of cmd line args to the device models based on the + # xm config file + def parseDeviceModelArgs(self, vmConfig): + ret = ["-domain-name", str(self.vm.info[''name_label''])] + + # Find RFB console device, and if it exists, make QEMU enable + # the VNC console. + if int(vmConfig[''platform''].get(''nographic'', 0)) != 0: + # skip vnc init if nographic is set + ret.append(''-nographic'') + return ret + + vnc_config = {} + has_vnc = int(vmConfig[''platform''].get(''vnc'', 0)) != 0 + has_sdl = int(vmConfig[''platform''].get(''sdl'', 0)) != 0 + for dev_uuid in vmConfig[''console_refs'']: + dev_type, dev_info = vmConfig[''devices''][dev_uuid] + if dev_type == ''vfb'': + vnc_config = dev_info.get(''other_config'', {}) + has_vnc = True + break + + keymap = vmConfig[''platform''].get("keymap") + if keymap: + ret.append("-k") + ret.append(keymap) + + if has_vnc: + if not vnc_config: + for key in (''vncunused'', ''vnclisten'', ''vncdisplay'', + ''vncpasswd''): + if key in vmConfig[''platform'']: + vnc_config[key] = vmConfig[''platform''][key] + + vnclisten = vnc_config.get(''vnclisten'', + xenopts().get_vnclisten_address()) + vncdisplay = vnc_config.get(''vncdisplay'', 0) + ret.append(''-vnc'') + ret.append("%s:%d" % (vnclisten, vncdisplay)) + + if vnc_config.get(''vncunused'', 0): + ret.append(''-vncunused'') + + # Store vncpassword in xenstore + vncpasswd = vnc_config.get(''vncpasswd'') + if not vncpasswd: + vncpasswd = xenopts().get_vncpasswd_default() + + if vncpasswd is None: + raise VmError(''vncpasswd is not setup in vmconfig or '' + ''xend-config.sxp'') + + if vncpasswd != '''': + self.vm.storeVm(''vncpasswd'', vncpasswd) + elif has_sdl: + # SDL is default in QEMU. + pass + else: + ret.append(''-nographic'') + + if int(vmConfig[''platform''].get(''monitor'', 0)) != 0: + ret = ret + [''-monitor'', ''vc''] + return ret + + def getDeviceModelArgs(self, restore = False): + args = [self.device_model] + args = args + ([ "-d", "%d" % self.vm.getDomid() ]) + args = args + self.dmargs + return args + def createDeviceModel(self, restore = False): - """Create device model for the domain (define in subclass if needed).""" - pass - + if self.device_model is None: + return + if self.pid: + return + # Execute device model. + #todo: Error handling + args = self.getDeviceModelArgs(restore) + env = dict(os.environ) + if self.display: + env[''DISPLAY''] = self.display + if self.xauthority: + env[''XAUTHORITY''] = self.xauthority + if self.vncconsole: + args = args + ([ "-vncviewer" ]) + log.info("spawning device models: %s %s", self.device_model, args) + # keep track of pid and spawned options to kill it later + self.pid = os.spawnve(os.P_NOWAIT, self.device_model, args, env) + self.vm.storeDom("image/device-model-pid", self.pid) + log.info("device model pid: %d", self.pid) + def saveDeviceModel(self): - """Save device model for the domain (define in subclass if needed).""" - pass + if self.device_model is None: + return + # Signal the device model to pause itself and save its state + xstransact.Store("/local/domain/0/device-model/%i" + % self.vm.getDomid(), (''command'', ''save'')) + # Wait for confirmation. Could do this with a watch but we''d + # still end up spinning here waiting for the watch to fire. + state = '''' + count = 0 + while state != ''paused'': + state = xstransact.Read("/local/domain/0/device-model/%i/state" + % self.vm.getDomid()) + time.sleep(0.1) + count += 1 + if count > 100: + raise VmError(''Timed out waiting for device model to save'') def resumeDeviceModel(self): - """Unpause device model for the domain (define in subclass if needed).""" - pass - - def destroy(self): - """Extra cleanup on domain destroy (define in subclass if needed).""" - pass - + if self.device_model is None: + return + # Signal the device model to resume activity after pausing to save. + xstransact.Store("/local/domain/0/device-model/%i" + % self.vm.getDomid(), (''command'', ''continue'')) def recreate(self): - pass + if self.device_model is None: + return + self.pid = self.vm.gatherDom((''image/device-model-pid'', int)) + + def destroyDeviceModel(self): + if self.device_model is None: + return + if self.pid: + try: + os.kill(self.pid, signal.SIGKILL) + except OSError, exn: + log.exception(exn) + try: + os.waitpid(self.pid, 0) + except OSError, exn: + # This is expected if Xend has been restarted within the + # life of this domain. In this case, we can kill the process, + # but we can''t wait for it because it''s not our child. + pass + self.pid = None + state = xstransact.Remove("/local/domain/0/device-model/%i" + % self.vm.getDomid()) class LinuxImageHandler(ImageHandler): @@ -223,6 +351,19 @@ class LinuxImageHandler(ImageHandler): ramdisk = self.ramdisk, features = self.vm.getFeatures()) + def parseDeviceModelArgs(self, vmConfig): + ret = ImageHandler.parseDeviceModelArgs(self, vmConfig) + # Equivalent to old xenconsoled behaviour. Should make + # it configurable in future + ret = ret + ["-serial", "pty"] + return ret + + def getDeviceModelArgs(self, restore = False): + args = ImageHandler.getDeviceModelArgs(self, restore) + args = args + ([ "-M", "xenpv"]) + return args + + class PPC_LinuxImageHandler(LinuxImageHandler): ostype = "linux" @@ -256,15 +397,6 @@ class HVMImageHandler(ImageHandler): if ''hvm'' not in info[''xen_caps'']: raise HVMRequired() - self.dmargs = self.parseDeviceModelArgs(vmConfig) - self.device_model = vmConfig[''platform''].get(''device_model'') - if not self.device_model: - raise VmError("hvm: missing device model") - - self.display = vmConfig[''platform''].get(''display'') - 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)), @@ -272,46 +404,17 @@ class HVMImageHandler(ImageHandler): ("image/display", self.display)) self.vm.storeVm(("rtc/timeoffset", rtc_timeoffset)) - self.pid = None - self.pae = int(vmConfig[''platform''].get(''pae'', 0)) self.apic = int(vmConfig[''platform''].get(''apic'', 0)) self.acpi = int(vmConfig[''platform''].get(''acpi'', 0)) - - - def buildDomain(self): - store_evtchn = self.vm.getStorePort() - - mem_mb = self.getRequiredInitialReservation() / 1024 - - log.debug("domid = %d", self.vm.getDomid()) - log.debug("image = %s", self.kernel) - log.debug("store_evtchn = %d", store_evtchn) - log.debug("memsize = %d", mem_mb) - log.debug("vcpus = %d", self.vm.getVCpuCount()) - log.debug("pae = %d", self.pae) - log.debug("acpi = %d", self.acpi) - log.debug("apic = %d", self.apic) - - rc = xc.hvm_build(domid = self.vm.getDomid(), - image = self.kernel, - store_evtchn = store_evtchn, - memsize = mem_mb, - vcpus = self.vm.getVCpuCount(), - pae = self.pae, - acpi = self.acpi, - apic = self.apic) - rc[''notes''] = { ''SUSPEND_CANCEL'': 1 } - return rc - - # Return a list of cmd line args to the device models based on the - # xm config file + def parseDeviceModelArgs(self, vmConfig): + ret = ImageHandler.parseDeviceModelArgs(self, vmConfig) + ret = ret + [''-vcpus'', str(self.vm.getVCpuCount())] + dmargs = [ ''boot'', ''fda'', ''fdb'', ''soundhw'', ''localtime'', ''serial'', ''stdvga'', ''isa'', - ''acpi'', ''usb'', ''usbdevice'', ''keymap'' ] - - ret = [''-vcpus'', str(self.vm.getVCpuCount())] + ''acpi'', ''usb'', ''usbdevice'' ] for a in dmargs: v = vmConfig[''platform''].get(a) @@ -340,7 +443,6 @@ class HVMImageHandler(ImageHandler): # Handle disk/network related options mac = None - ret = ret + ["-domain-name", str(self.vm.info[''name_label''])] nics = 0 for devuuid in vmConfig[''vbd_refs'']: @@ -369,130 +471,40 @@ class HVMImageHandler(ImageHandler): ret.append("-net") ret.append("tap,vlan=%d,bridge=%s" % (nics, bridge)) - - # - # Find RFB console device, and if it exists, make QEMU enable - # the VNC console. - # - if int(vmConfig[''platform''].get(''nographic'', 0)) != 0: - # skip vnc init if nographic is set - ret.append(''-nographic'') - return ret - - vnc_config = {} - has_vnc = int(vmConfig[''platform''].get(''vnc'', 0)) != 0 - has_sdl = int(vmConfig[''platform''].get(''sdl'', 0)) != 0 - for dev_uuid in vmConfig[''console_refs'']: - dev_type, dev_info = vmConfig[''devices''][dev_uuid] - if dev_type == ''vfb'': - vnc_config = dev_info.get(''other_config'', {}) - has_vnc = True - break - - if has_vnc: - if not vnc_config: - for key in (''vncunused'', ''vnclisten'', ''vncdisplay'', - ''vncpasswd''): - if key in vmConfig[''platform'']: - vnc_config[key] = vmConfig[''platform''][key] - - vnclisten = vnc_config.get(''vnclisten'', - xenopts().get_vnclisten_address()) - vncdisplay = vnc_config.get(''vncdisplay'', 0) - ret.append(''-vnc'') - ret.append("%s:%d" % (vnclisten, vncdisplay)) - - if vnc_config.get(''vncunused'', 0): - ret.append(''-vncunused'') - - # Store vncpassword in xenstore - vncpasswd = vnc_config.get(''vncpasswd'') - if not vncpasswd: - vncpasswd = xenopts().get_vncpasswd_default() - - if vncpasswd is None: - raise VmError(''vncpasswd is not setup in vmconfig or '' - ''xend-config.sxp'') - - if vncpasswd != '''': - self.vm.storeVm(''vncpasswd'', vncpasswd) - elif has_sdl: - # SDL is default in QEMU. - pass - else: - ret.append(''-nographic'') - - if int(vmConfig[''platform''].get(''monitor'', 0)) != 0: - ret = ret + [''-monitor'', ''vc''] return ret - def createDeviceModel(self, restore = False): - if self.pid: - return - # Execute device model. - #todo: Error handling - args = [self.device_model] - args = args + ([ "-d", "%d" % self.vm.getDomid() ]) - if arch.type == "ia64": - args = args + ([ "-m", "%s" % - (self.getRequiredInitialReservation() / 1024) ]) - args = args + self.dmargs + def getDeviceModelArgs(self, restore = False): + args = ImageHandler.getDeviceModelArgs(self, restore) + args = args + ([ "-M", "xenfv"]) if restore: args = args + ([ "-loadvm", "/var/lib/xen/qemu-save.%d" % self.vm.getDomid() ]) - env = dict(os.environ) - if self.display: - env[''DISPLAY''] = self.display - if self.xauthority: - env[''XAUTHORITY''] = self.xauthority - if self.vncconsole: - args = args + ([ "-vncviewer" ]) - log.info("spawning device models: %s %s", self.device_model, args) - # keep track of pid and spawned options to kill it later - self.pid = os.spawnve(os.P_NOWAIT, self.device_model, args, env) - self.vm.storeDom("image/device-model-pid", self.pid) - log.info("device model pid: %d", self.pid) - - def saveDeviceModel(self): - # Signal the device model to pause itself and save its state - xstransact.Store("/local/domain/0/device-model/%i" - % self.vm.getDomid(), (''command'', ''save'')) - # Wait for confirmation. Could do this with a watch but we''d - # still end up spinning here waiting for the watch to fire. - state = '''' - count = 0 - while state != ''paused'': - state = xstransact.Read("/local/domain/0/device-model/%i/state" - % self.vm.getDomid()) - time.sleep(0.1) - count += 1 - if count > 100: - raise VmError(''Timed out waiting for device model to save'') - - def resumeDeviceModel(self): - # Signal the device model to resume activity after pausing to save. - xstransact.Store("/local/domain/0/device-model/%i" - % self.vm.getDomid(), (''command'', ''continue'')) - - def recreate(self): - self.pid = self.vm.gatherDom((''image/device-model-pid'', int)) - - def destroy(self, suspend = False): - if self.pid and not suspend: - try: - os.kill(self.pid, signal.SIGKILL) - except OSError, exn: - log.exception(exn) - try: - os.waitpid(self.pid, 0) - except OSError, exn: - # This is expected if Xend has been restarted within the - # life of this domain. In this case, we can kill the process, - # but we can''t wait for it because it''s not our child. - pass - self.pid = None - state = xstransact.Remove("/local/domain/0/device-model/%i" - % self.vm.getDomid()) + return args + + def buildDomain(self): + store_evtchn = self.vm.getStorePort() + + mem_mb = self.getRequiredInitialReservation() / 1024 + + log.debug("domid = %d", self.vm.getDomid()) + log.debug("image = %s", self.kernel) + log.debug("store_evtchn = %d", store_evtchn) + log.debug("memsize = %d", mem_mb) + log.debug("vcpus = %d", self.vm.getVCpuCount()) + log.debug("pae = %d", self.pae) + log.debug("acpi = %d", self.acpi) + log.debug("apic = %d", self.apic) + + rc = xc.hvm_build(domid = self.vm.getDomid(), + image = self.kernel, + store_evtchn = store_evtchn, + memsize = mem_mb, + vcpus = self.vm.getVCpuCount(), + pae = self.pae, + acpi = self.acpi, + apic = self.apic) + rc[''notes''] = { ''SUSPEND_CANCEL'': 1 } + return rc class IA64_HVM_ImageHandler(HVMImageHandler): @@ -514,6 +526,13 @@ class IA64_HVM_ImageHandler(HVMImageHand def getRequiredShadowMemory(self, shadow_mem_kb, maxmem_kb): # Explicit shadow memory is not a concept return 0 + + def getDeviceModelArgs(self, restore = False): + args = HVMImageHandler.getDeviceModelArgs(self, restore) + args = args + ([ "-m", "%s" % + (self.getRequiredInitialReservation() / 1024) ]) + return args + class X86_HVM_ImageHandler(HVMImageHandler): diff -r 912986c9283d tools/python/xen/xend/server/vfbif.py --- a/tools/python/xen/xend/server/vfbif.py Wed Aug 22 16:17:45 2007 -0400 +++ b/tools/python/xen/xend/server/vfbif.py Wed Aug 22 16:17:49 2007 -0400 @@ -5,14 +5,6 @@ import xen.xend import xen.xend import os -def spawn_detached(path, args, env): - p = os.fork() - if p == 0: - os.spawnve(os.P_NOWAIT, path, args, env) - os._exit(0) - else: - os.waitpid(p, 0) - CONFIG_ENTRIES = [''type'', ''vncdisplay'', ''vnclisten'', ''vncpasswd'', ''vncunused'', ''display'', ''xauthority'', ''keymap'', ''uuid'', ''location'', ''protocol''] @@ -43,65 +35,9 @@ class VfbifController(DevController): for i in range(len(CONFIG_ENTRIES)) if devinfo[i] is not None]) - - def createDevice(self, config): - DevController.createDevice(self, config) - if self.vm.info.is_hvm(): - # is HVM, so qemu-dm will handle the vfb. - return - - args = [ xen.util.auxbin.pathTo("qemu-dm"), - "-M", "xenpv", - "-d", "%d" % self.vm.getDomid(), - "-domain-name", self.vm.getName() ] - t = config.get("type", None) - if t == "vnc": - passwd = None - if config.has_key("vncpasswd"): - passwd = config["vncpasswd"] - else: - passwd = xen.xend.XendOptions.instance().get_vncpasswd_default() - if passwd: - self.vm.storeVm("vncpasswd", passwd) - log.debug("Stored a VNC password for vfb access") - else: - log.debug("No VNC passwd configured for vfb access") - - vnclisten = config.get(''vnclisten'', - xen.xend.XendOptions.instance().get_vnclisten_address()) - vncdisplay = config.get(''vncdisplay'', 0) - args += [''-vnc'', "%s:%d" % (vnclisten, vncdisplay)] - - if config.get(''vncunused'', 0): - args += [''-vncunused''] - - if config.has_key("keymap"): - args += ["-k", "%s" % config["keymap"]] - else: - xoptions = xen.xend.XendOptions.instance() - if xoptions.get_keymap(): - args += ["-k", "%s" % xoptions.get_keymap()] - - spawn_detached(args[0], args, os.environ) - elif t == "sdl": - env = dict(os.environ) - if config.has_key("display"): - env[''DISPLAY''] = config["display"] - if config.has_key("xauthority"): - env[''XAUTHORITY''] = config["xauthority"] - spawn_detached(args[0], args, env) - else: - raise VmError(''Unknown vfb type %s (%s)'' % (t, repr(config))) - - def waitForDevice(self, devid): - if self.vm.info.get(''HVM_boot_policy''): - log.debug(''skip waiting for HVM vfb'') - # is a qemu-dm managed device, don''t wait for hotplug for these. - return - - DevController.waitForDevice(self, devid) - + # is a qemu-dm managed device, don''t wait for hotplug for these. + return def reconfigureDevice(self, _, config): """ Only allow appending location information of vnc port into @@ -115,20 +51,15 @@ class VfbifController(DevController): raise VmError(''Refusing to reconfigure device vfb:%d'' % devid) def destroyDevice(self, devid, force): - if self.vm.info.get(''HVM_boot_policy''): - # remove the backend xenstore entries for HVM guests no matter - # what - DevController.destroyDevice(self, devid, True) - else: - DevController.destroyDevice(self, devid, force) - + # remove the backend xenstore entries no matter what + # because we kill qemu-dm with extreme prejudice + # not giving it a chance to remove them itself + DevController.destroyDevice(self, devid, True) def migrate(self, deviceConfig, network, dst, step, domName): - if self.vm.info.get(''HVM_boot_policy''): - return 0 - return DevController.migrate(self, deviceConfig, network, dst, step, - domName) - + # Handled by qemu-dm so no action needed + return 0 + class VkbdifController(DevController): """Virtual keyboard controller. Handles all vkbd devices for a domain. """ @@ -141,22 +72,15 @@ class VkbdifController(DevController): return (devid, back, front) def waitForDevice(self, config): - if self.vm.info.get(''HVM_boot_policy''): - # is a qemu-dm managed device, don''t wait for hotplug for these. - return - - DevController.waitForDevice(self, config) + # is a qemu-dm managed device, don''t wait for hotplug for these. + return def destroyDevice(self, devid, force): - if self.vm.info.get(''HVM_boot_policy''): - # remove the backend xenstore entries for HVM guests no matter - # what - DevController.destroyDevice(self, devid, True) - else: - DevController.destroyDevice(self, devid, force) + # remove the backend xenstore entries no matter what + # because we kill qemu-dm with extreme prejudice + # not giving it a chance to remove them itself + DevController.destroyDevice(self, devid, True) def migrate(self, deviceConfig, network, dst, step, domName): - if self.vm.info.get(''HVM_boot_policy''): - return 0 - return DevController.migrate(self, deviceConfig, network, dst, step, - domName) + # Handled by qemu-dm so no action needed + return 0 -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=| _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel P. Berrange
2007-Aug-22 22:34 UTC
Re: [Xen-devel] PATCH: 10/10: Make xenconsoled ignore doms with qemu-dm
This patch writes a field /local/vm/DOMID/console/type taking the value ''ioemu'' or ''xenconsoled''. If xenconsoled sees a type that is not its own, then it skips handling of that guest. The qemu-dm process doesn''t need to read this field since it will only attach to the console if given the -serial pty arg which XenD already ensures matches this xenstore field. The overall behaviour is that if a paravirt guest has a qemu-dm process running then that handles the console, otherwise the xenconsoled handles it. The former is more functional, with the exception of not currently supporting persistent logging to a file at the same time as exposing a PTY. console/daemon/io.c | 9 +++++++++ python/xen/xend/XendDomainInfo.py | 7 +++++++ 2 files changed, 16 insertions(+) Signed-off-by: Daniel P. Berrange <berrange@redhat.com> Dan. diff -r 4559faae3790 tools/console/daemon/io.c --- a/tools/console/daemon/io.c Wed Aug 22 16:24:48 2007 -0400 +++ b/tools/console/daemon/io.c Wed Aug 22 18:48:05 2007 -0400 @@ -327,6 +327,7 @@ static int domain_create_ring(struct dom static int domain_create_ring(struct domain *dom) { int err, remote_port, ring_ref, rc; + char *type, path[PATH_MAX]; err = xs_gather(xs, dom->serialpath, "ring-ref", "%u", &ring_ref, @@ -343,6 +344,14 @@ static int domain_create_ring(struct dom } else dom->use_consolepath = 0; + sprintf(path, "%s/type", dom->use_consolepath ? dom->conspath: dom->serialpath); + type = xs_read(xs, XBT_NULL, path, NULL); + if (type && strcmp(type, "xenconsoled") != 0) { + free(type); + return 0; + } + free(type); + if ((ring_ref == dom->ring_ref) && (remote_port == dom->remote_port)) goto out; diff -r 4559faae3790 tools/python/xen/xend/XendDomainInfo.py --- a/tools/python/xen/xend/XendDomainInfo.py Wed Aug 22 16:24:48 2007 -0400 +++ b/tools/python/xen/xend/XendDomainInfo.py Wed Aug 22 18:36:15 2007 -0400 @@ -883,8 +883,15 @@ class XendDomainInfo: else: to_store[n] = str(v) + # Figure out if we need to tell xenconsoled to ignore this guest''s + # console - device model will handle console if it is running + constype = "ioemu" + if ''device_model'' not in self.info[''platform'']: + constype = "xenconsoled" + f(''console/port'', self.console_port) f(''console/ring-ref'', self.console_mfn) + f(''console/type'', constype) f(''store/port'', self.store_port) f(''store/ring-ref'', self.store_mfn) -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=| _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel P. Berrange
2007-Aug-28 15:01 UTC
Re: [Xen-devel] PATCH: 0/10: Merge paravirt FB & console into qemu-dm
On Wed, Aug 22, 2007 at 11:26:53PM +0100, Daniel P. Berrange wrote:> The following series of 10 patches is a merge of the xenfb and xenconsoled > functionality into the qemu-dm code. The general approach taken is to have > qemu-dm provide two machine types - one for xen paravirt, the other for > fullyvirt. For compatability the later is the default. The goals overall > are to kill LibVNCServer, remove alot of code duplication and/or parallel > impls of the same concepts, and increase the functionality for PV. In > particular this will let paravirt guests take advantage of TLS encryption > for the VNC server, and let us configure the text console in all the variety > of ways QEMU supports (PTY, File, TCP, TCP_Telnet,UDP, etc).Markus has suggested a couple of changes to make on some of the patches in this series, so don''t apply them to xen-unstable yet. I''ll post a new set in a few days time. Regards, Dan. -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=| _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel