Daniel P. Berrange
2007-Oct-24 20:35 UTC
[Xen-devel] PATCH 0/10: Merge PV framebuffer & console into QEMU
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 - to assist bisecting, 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. 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 | 779 ---------------------- a/tools/xenfb/xenfb.h | 35 - b/tools/ioemu/hw/xen_console.c | 432 ++++++++++++ b/tools/ioemu/hw/xen_console.h | 25 b/tools/ioemu/hw/xen_machine_fv.c | 288 ++++++++ b/tools/ioemu/hw/xen_machine_pv.c | 73 ++ b/tools/ioemu/hw/xenfb.c | 1108 ++++++++++++++++++++++++++++++++ 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 | 37 - tools/python/xen/xend/image.py | 382 +++++------ tools/python/xen/xend/server/vfbif.py | 108 --- 27 files changed, 2231 insertions(+), 2329 deletions(-) The entire series is synced against xen-unstable.hg 16157:b28ae5f00553 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-Oct-24 20:39 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 | 288 ++++++++++++++++++++++++++++++++++++++ tools/ioemu/Makefile.target | 1 tools/ioemu/vl.c | 244 -------------------------------- tools/ioemu/vl.h | 3 4 files changed, 297 insertions(+), 239 deletions(-) Signed-off-by: Daniel P. Berrange <berrange@redhat.com> diff -r b28ae5f00553 tools/ioemu/Makefile.target --- a/tools/ioemu/Makefile.target Tue Oct 23 09:26:43 2007 +0100 +++ b/tools/ioemu/Makefile.target Wed Oct 24 15:20:39 2007 -0400 @@ -409,6 +409,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 b28ae5f00553 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 Oct 24 15:24:39 2007 -0400 @@ -0,0 +1,288 @@ +/* + * 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)); + + /* + * 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); + fprintf(logfile, "qemu_map_cache_init nr_buckets = %lx size %lu\n", nr_buckets, size); + mapcache_entry = mmap(NULL, size, PROT_READ|PROT_WRITE, + MAP_SHARED|MAP_ANON, -1, 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] >> 28) & 0xf) != 0xf); + 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, + const char *direct_pci) +{ + 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, + direct_pci); +} + +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 b28ae5f00553 tools/ioemu/vl.c --- a/tools/ioemu/vl.c Tue Oct 23 09:26:43 2007 +0100 +++ b/tools/ioemu/vl.c Wed Oct 24 15:21:37 2007 -0400 @@ -96,7 +96,6 @@ #include "exec-all.h" -#include <xen/hvm/params.h> #define DEFAULT_NETWORK_SCRIPT "/etc/xen/qemu-ifup" #ifdef _BSD #define DEFAULT_BRIDGE "bridge0" @@ -6696,8 +6695,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); @@ -6905,156 +6908,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)); - - /* - * 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); - fprintf(logfile, "qemu_map_cache_init nr_buckets = %lx size %lu\n", nr_buckets, size); - mapcache_entry = mmap(NULL, size, PROT_READ|PROT_WRITE, - MAP_SHARED|MAP_ANON, -1, 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] >> 28) & 0xf) != 0xf); - 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) { @@ -7089,15 +6942,7 @@ 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; struct rlimit rl; -#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]; const char *direct_pci = NULL; @@ -7681,6 +7526,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 */ @@ -7774,83 +7620,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) { @@ -7858,9 +7627,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 b28ae5f00553 tools/ioemu/vl.h --- a/tools/ioemu/vl.h Tue Oct 23 09:26:43 2007 +0100 +++ b/tools/ioemu/vl.h Wed Oct 24 15:20:39 2007 -0400 @@ -1108,6 +1108,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-Oct-24 20:40 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. The overall VIRT memory image size is about same as old xen-vncfb, but the resident memory size is a little increased due to copy of the framebuffer & some QEMU static state overhead. Most of this is shared across QEMU processes. 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 | 315 ++++++++++++++++++++++++++++++++++ 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, 401 insertions(+), 37 deletions(-) Signed-off-by: Daniel P. Berrange <berrange@redhat.com> diff -r 6081d29591f1 tools/ioemu/Makefile.target --- a/tools/ioemu/Makefile.target Tue Sep 11 11:26:39 2007 -0400 +++ b/tools/ioemu/Makefile.target Tue Sep 11 11:28:21 2007 -0400 @@ -400,6 +400,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 6081d29591f1 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 Sep 11 11:28:21 2007 -0400 @@ -0,0 +1,315 @@ +/* + * 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> + +/* + * Tables to map from scancode to Linux input layer keycode. + * Scancodes are hardware-specific. These maps assumes a + * standard AT or PS/2 keyboard which is what QEMU feeds us. + */ +static const 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 const 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 + +}; + +static unsigned char scancode2linux[512]; + +/* 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 key event from the client to the guest OS + * QEMU gives us a raw scancode from an AT / PS/2 style keyboard. + * We have to turn this into a Linux Input layer keycode. + * + * Extra complexity from the fact that with extended scancodes + * (like those produced by arrow keys) this method gets called + * twice, but we only want to send a single event. So we have to + * track the ''0xe0'' scancode state & collapse the extended keys + * as needed. + * + * Wish we could just send scancodes straight to the guest which + * already has code for dealing with this... + */ +static void xen_pvfb_key_event(void *opaque, int scancode) +{ + static int extended = 0; + int down = 1; + if (scancode == 0xe0) { + extended = 1; + return; + } else if (scancode & 0x80) { + scancode &= 0x7f; + down = 0; + } + if (extended) { + scancode |= 0x80; + extended = 0; + } + xenfb_send_key(opaque, down, scancode2linux[scancode]); +} + +/* + * Send a mouse event from the client to the guest OS + * + * The QEMU mouse can be in either relative, or absolute mode. + * Movement is sent separately from button state, which has to + * be encoded as virtual key events. We also don''t actually get + * given any button up/down events, so have to track changes in + * the button state. + */ +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 = 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 */ +/* XXX - can we optimize this, or the next func at all ? */ +void xen_pvfb_update(void *opaque) +{ + struct xenfb *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) +{ + xen_pvfb_update(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(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(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, i; + + /* Prepare scancode mapping table */ + for (i = 0; i < 128; i++) { + scancode2linux[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]]; + scancode2linux[i | 0x80] = + atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80]; + } + + /* 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_key_event, 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 6081d29591f1 tools/ioemu/target-i386-dm/helper2.c --- a/tools/ioemu/target-i386-dm/helper2.c Tue Sep 11 11:26:39 2007 -0400 +++ b/tools/ioemu/target-i386-dm/helper2.c Tue Sep 11 11:28:21 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 6081d29591f1 tools/ioemu/vl.c --- a/tools/ioemu/vl.c Tue Sep 11 11:26:39 2007 -0400 +++ b/tools/ioemu/vl.c Tue Sep 11 11:28:21 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 6081d29591f1 tools/ioemu/vl.h --- a/tools/ioemu/vl.h Tue Sep 11 11:26:39 2007 -0400 +++ b/tools/ioemu/vl.h Tue Sep 11 11:28:21 2007 -0400 @@ -1110,6 +1110,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 6081d29591f1 tools/python/xen/xend/server/vfbif.py --- a/tools/python/xen/xend/server/vfbif.py Tue Sep 11 11:26:39 2007 -0400 +++ b/tools/python/xen/xend/server/vfbif.py Tue Sep 11 11:28:21 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 6081d29591f1 tools/xenfb/xenfb.c --- a/tools/xenfb/xenfb.c Tue Sep 11 11:26:39 2007 -0400 +++ b/tools/xenfb/xenfb.c Tue Sep 11 11:28:21 2007 -0400 @@ -670,37 +670,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; @@ -715,6 +736,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, @@ -777,3 +810,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 6081d29591f1 tools/xenfb/xenfb.h --- a/tools/xenfb/xenfb.h Tue Sep 11 11:26:39 2007 -0400 +++ b/tools/xenfb/xenfb.h Tue Sep 11 11:28:21 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-Oct-24 20:40 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 | 819 --------------------------------------- a/tools/xenfb/xenfb.h | 39 - b/tools/ioemu/hw/xenfb.c | 819 +++++++++++++++++++++++++++++++++++++++ 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, 862 insertions(+), 1825 deletions(-) Signed-off-by: Daniel P. Berrange <berrange@redhat.com> diff -r 402c7c3fcf94 Config.mk --- a/Config.mk Tue Sep 11 11:28:21 2007 -0400 +++ b/Config.mk Tue Sep 11 11:37:36 2007 -0400 @@ -88,7 +88,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 402c7c3fcf94 tools/Makefile --- a/tools/Makefile Tue Sep 11 11:28:21 2007 -0400 +++ b/tools/Makefile Tue Sep 11 11:37:36 2007 -0400 @@ -20,7 +20,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 402c7c3fcf94 tools/check/Makefile --- a/tools/check/Makefile Tue Sep 11 11:28:21 2007 -0400 +++ b/tools/check/Makefile Tue Sep 11 11:37:36 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) ACM_SECURITY=$(ACM_SECURITY) ./chk build + LIBXENAPI_BINDINGS=$(LIBXENAPI_BINDINGS) ACM_SECURITY=$(ACM_SECURITY) ./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) ACM_SECURITY=$(ACM_SECURITY) ./chk install + LIBXENAPI_BINDINGS=$(LIBXENAPI_BINDINGS) ACM_SECURITY=$(ACM_SECURITY) ./chk install .PHONY: clean clean: diff -r 402c7c3fcf94 tools/check/check_libvncserver --- a/tools/check/check_libvncserver Tue Sep 11 11:28:21 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 402c7c3fcf94 tools/check/check_sdl --- a/tools/check/check_sdl Tue Sep 11 11:28:21 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 402c7c3fcf94 tools/ioemu/Makefile.target --- a/tools/ioemu/Makefile.target Tue Sep 11 11:28:21 2007 -0400 +++ b/tools/ioemu/Makefile.target Tue Sep 11 11:37:36 2007 -0400 @@ -401,7 +401,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 402c7c3fcf94 tools/ioemu/hw/xen_machine_pv.c --- a/tools/ioemu/hw/xen_machine_pv.c Tue Sep 11 11:28:21 2007 -0400 +++ b/tools/ioemu/hw/xen_machine_pv.c Tue Sep 11 11:37:36 2007 -0400 @@ -23,7 +23,7 @@ */ #include "vl.h" -#include "../../xenfb/xenfb.h" +#include "xenfb.h" #include <linux/input.h> /* diff -r 402c7c3fcf94 tools/ioemu/hw/xenfb.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/ioemu/hw/xenfb.c Tue Sep 11 11:37:36 2007 -0400 @@ -0,0 +1,819 @@ +#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; + + xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd); + map = xc_map_foreign_pages(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_pages(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 402c7c3fcf94 tools/ioemu/hw/xenfb.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/ioemu/hw/xenfb.h Tue Sep 11 11:37:36 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 402c7c3fcf94 tools/xenfb/Makefile --- a/tools/xenfb/Makefile Tue Sep 11 11:28:21 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 402c7c3fcf94 tools/xenfb/sdlfb.c --- a/tools/xenfb/sdlfb.c Tue Sep 11 11:28:21 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 402c7c3fcf94 tools/xenfb/vncfb.c --- a/tools/xenfb/vncfb.c Tue Sep 11 11:28:21 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 402c7c3fcf94 tools/xenfb/xenfb.c --- a/tools/xenfb/xenfb.c Tue Sep 11 11:28:21 2007 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,819 +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; - - xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd); - map = xc_map_foreign_pages(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_pages(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 402c7c3fcf94 tools/xenfb/xenfb.h --- a/tools/xenfb/xenfb.h Tue Sep 11 11:28:21 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-Oct-24 20:41 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 | 31 ------ xenfb.c | 249 +++++++++++++++++++++++-------------------------------- xenfb.h | 7 - 3 files changed, 107 insertions(+), 180 deletions(-) Signed-off-by: Daniel P. Berrange <berrange@redhat.com> diff -r d25e2cb62784 tools/ioemu/hw/xen_machine_pv.c --- a/tools/ioemu/hw/xen_machine_pv.c Tue Sep 11 11:37:37 2007 -0400 +++ b/tools/ioemu/hw/xen_machine_pv.c Tue Sep 11 11:53:28 2007 -0400 @@ -213,22 +213,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(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(opaque)) < 0) { - fprintf(stderr, "Failure while dispatching store: %d\n", ret); - exit(1); - } -} - /* The Xen PV machine currently provides * - a virtual framebuffer * - .... @@ -242,7 +226,7 @@ static void xen_init_pv(uint64_t ram_siz { struct xenfb *xenfb; extern int domid; - int fd, i; + int i; /* Prepare scancode mapping table */ for (i = 0; i < 128; i++) { @@ -281,19 +265,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 d25e2cb62784 tools/ioemu/hw/xenfb.c --- a/tools/ioemu/hw/xenfb.c Tue Sep 11 11:37:37 2007 -0400 +++ b/tools/ioemu/hw/xenfb.c Tue Sep 11 11:53:28 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? @@ -505,96 +505,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) { @@ -670,13 +580,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); @@ -684,12 +594,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; @@ -702,52 +610,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 d25e2cb62784 tools/ioemu/hw/xenfb.h --- a/tools/ioemu/hw/xenfb.h Tue Sep 11 11:37:37 2007 -0400 +++ b/tools/ioemu/hw/xenfb.h Tue Sep 11 11:53:28 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-Oct-24 20:41 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 | 214 --------------------------------- xenfb.c | 353 +++++++++++++++++++++++++++++++++++++++++++++---------- xenfb.h | 8 - 3 files changed, 294 insertions(+), 281 deletions(-) Signed-off-by: Daniel P. Berrange <berrange@redhat.com> diff -r 93300915575f tools/ioemu/hw/xen_machine_pv.c --- a/tools/ioemu/hw/xen_machine_pv.c Tue Sep 11 11:53:28 2007 -0400 +++ b/tools/ioemu/hw/xen_machine_pv.c Tue Sep 11 11:53:34 2007 -0400 @@ -24,194 +24,6 @@ #include "vl.h" #include "xenfb.h" -#include <linux/input.h> - -/* - * Tables to map from scancode to Linux input layer keycode. - * Scancodes are hardware-specific. These maps assumes a - * standard AT or PS/2 keyboard which is what QEMU feeds us. - */ -static const 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 const 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 - -}; - -static unsigned char scancode2linux[512]; - -/* 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 key event from the client to the guest OS - * QEMU gives us a raw scancode from an AT / PS/2 style keyboard. - * We have to turn this into a Linux Input layer keycode. - * - * Extra complexity from the fact that with extended scancodes - * (like those produced by arrow keys) this method gets called - * twice, but we only want to send a single event. So we have to - * track the ''0xe0'' scancode state & collapse the extended keys - * as needed. - * - * Wish we could just send scancodes straight to the guest which - * already has code for dealing with this... - */ -static void xen_pvfb_key_event(void *opaque, int scancode) -{ - static int extended = 0; - int down = 1; - if (scancode == 0xe0) { - extended = 1; - return; - } else if (scancode & 0x80) { - scancode &= 0x7f; - down = 0; - } - if (extended) { - scancode |= 0x80; - extended = 0; - } - xenfb_send_key(opaque, down, scancode2linux[scancode]); -} - -/* - * Send a mouse event from the client to the guest OS - * - * The QEMU mouse can be in either relative, or absolute mode. - * Movement is sent separately from button state, which has to - * be encoded as virtual key events. We also don''t actually get - * given any button up/down events, so have to track changes in - * the button state. - */ -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 = 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 */ -/* XXX - can we optimize this, or the next func at all ? */ -void xen_pvfb_update(void *opaque) -{ - struct xenfb *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) -{ - xen_pvfb_update(opaque); -} - -/* 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 * - a virtual framebuffer @@ -226,14 +38,6 @@ static void xen_init_pv(uint64_t ram_siz { struct xenfb *xenfb; extern int domid; - int i; - - /* Prepare scancode mapping table */ - for (i = 0; i < 128; i++) { - scancode2linux[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]]; - scancode2linux[i | 0x80] = - atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80]; - } /* Prepare PVFB state */ xenfb = xenfb_new(); @@ -244,27 +48,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_key_event, 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); diff -r 93300915575f tools/ioemu/hw/xenfb.c --- a/tools/ioemu/hw/xenfb.c Tue Sep 11 11:53:28 2007 -0400 +++ b/tools/ioemu/hw/xenfb.c Tue Sep 11 11:53:34 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? @@ -43,6 +43,58 @@ struct xenfb_private { char protocol[64]; /* frontend protocol */ }; +/* Functions which tie the PVFB into the QEMU device model */ +static void xenfb_key_event(void *opaque, int keycode); +static void xenfb_mouse_event(void *opaque, + int dx, int dy, int dz, int button_state); +static void xenfb_guest_copy(struct xenfb *xenfb, int x, int y, int w, int h); +static void xenfb_update(void *opaque); +static void xenfb_invalidate(void *opaque); +static void xenfb_screen_dump(void *opaque, const char *name); + +/* + * Tables to map from scancode to Linux input layer keycode. + * Scancodes are hardware-specific. These maps assumes a + * standard AT or PS/2 keyboard which is what QEMU feeds us. + */ +static const 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 const 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 + +}; + +static unsigned char scancode2linux[512]; + + static void xenfb_detach_dom(struct xenfb_private *); static char *xenfb_path_in_dom(struct xs_handle *xsh, @@ -158,9 +210,17 @@ struct xenfb *xenfb_new(void) { struct xenfb_private *xenfb = malloc(sizeof(*xenfb)); int serrno; + int i; if (xenfb == NULL) return NULL; + + /* Prepare scancode mapping table */ + for (i = 0; i < 128; i++) { + scancode2linux[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]]; + scancode2linux[i | 0x80] = + atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80]; + } memset(xenfb, 0, sizeof(*xenfb)); xenfb->evt_xch = xenfb->xc = -1; @@ -580,6 +640,68 @@ 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); +} + + static void xenfb_dispatch_channel(void *xenfb_pub) { struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; @@ -614,7 +736,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; @@ -702,6 +824,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_key_event, 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: @@ -713,66 +852,154 @@ 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); -} +/* + * Send a key event from the client to the guest OS + * QEMU gives us a raw scancode from an AT / PS/2 style keyboard. + * We have to turn this into a Linux Input layer keycode. + * + * Extra complexity from the fact that with extended scancodes + * (like those produced by arrow keys) this method gets called + * twice, but we only want to send a single event. So we have to + * track the ''0xe0'' scancode state & collapse the extended keys + * as needed. + * + * Wish we could just send scancodes straight to the guest which + * already has code for dealing with this... + */ +static void xenfb_key_event(void *opaque, int scancode) +{ + static int extended = 0; + int down = 1; + if (scancode == 0xe0) { + extended = 1; + return; + } else if (scancode & 0x80) { + scancode &= 0x7f; + down = 0; + } + if (extended) { + scancode |= 0x80; + extended = 0; + } + xenfb_send_key(opaque, down, scancode2linux[scancode]); +} + +/* + * Send a mouse event from the client to the guest OS + * + * The QEMU mouse can be in either relative, or absolute mode. + * Movement is sent separately from button state, which has to + * be encoded as virtual key events. We also don''t actually get + * given any button up/down events, so have to track changes in + * the button state. + */ +static void xenfb_mouse_event(void *opaque, + int dx, int dy, int dz, int button_state) +{ + int i; + struct xenfb *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. + * When shifting between colour depths we preserve the MSB. + */ +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 */ +/* XXX - can we optimize this, or the next func at all ? */ +static void xenfb_update(void *opaque) +{ + struct xenfb *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 = opaque; + xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height); +} + +/* Screen dump is not used in Xen, so no need to impl this....yet */ +static void xenfb_screen_dump(void *opaque, const char *name) { } + + /* * Local variables: * c-indent-level: 8 diff -r 93300915575f tools/ioemu/hw/xenfb.h --- a/tools/ioemu/hw/xenfb.h Tue Sep 11 11:53:28 2007 -0400 +++ b/tools/ioemu/hw/xenfb.h Tue Sep 11 11:53:34 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-Oct-24 20:42 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). xen_machine_pv.c | 3 xenfb.c | 166 ++++++++++++++++++++++++++----------------------------- xenfb.h | 16 ----- 3 files changed, 82 insertions(+), 103 deletions(-) Signed-off-by: Daniel P. Berrange <berrange@redhat.com> diff -r 58cc6fb7824c tools/ioemu/hw/xen_machine_pv.c --- a/tools/ioemu/hw/xen_machine_pv.c Tue Sep 11 11:53:35 2007 -0400 +++ b/tools/ioemu/hw/xen_machine_pv.c Tue Sep 11 11:55:15 2007 -0400 @@ -53,9 +53,6 @@ static void xen_init_pv(uint64_t ram_siz strerror(errno)); exit(1); } - - /* Setup QEMU display */ - dpy_resize(ds, xenfb->width, xenfb->height); } QEMUMachine xenpv_machine = { diff -r 58cc6fb7824c tools/ioemu/hw/xenfb.c --- a/tools/ioemu/hw/xenfb.c Tue Sep 11 11:53:35 2007 -0400 +++ b/tools/ioemu/hw/xenfb.c Tue Sep 11 11:55:15 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,16 +32,23 @@ 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 { + DisplayState *ds; /* QEMU graphical console state */ int evt_xch; /* event channel driver handle */ int xc; /* hypervisor interface handle */ struct xs_handle *xsh; /* xs daemon handle */ struct xenfb_device fb, kbd; + void *pixels; /* guest framebuffer data */ size_t fb_len; /* size of framebuffer */ + int row_stride; /* width of one row in framebuffer */ + int depth; /* colour depth of guest framebuffer */ + int width; /* pixel width of guest framebuffer */ + int height; /* pixel height of guest framebuffer */ + int abs_pointer_wanted; /* Whether guest supports absolute pointer */ + int button_state; /* Last seen pointer button state */ char protocol[64]; /* frontend protocol */ }; @@ -95,7 +104,7 @@ static unsigned char scancode2linux[512] static unsigned char scancode2linux[512]; -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, @@ -176,7 +185,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; @@ -184,19 +193,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; @@ -208,7 +215,7 @@ int xenfb_device_set_domain(struct xenfb struct xenfb *xenfb_new(void) { - struct xenfb_private *xenfb = malloc(sizeof(*xenfb)); + struct xenfb *xenfb = qemu_malloc(sizeof(struct xenfb)); int serrno; int i; @@ -239,30 +246,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); @@ -394,7 +397,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; @@ -466,9 +469,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_pages(xenfb->xc, domid, + xenfb->pixels = xc_map_foreign_pages(xenfb->xc, domid, PROT_READ | PROT_WRITE, fbmfns, n_fbmfns); - if (xenfb->pub.pixels == NULL) + if (xenfb->pixels == NULL) goto out; ret = 0; /* all is fine */ @@ -483,7 +486,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; @@ -566,17 +569,18 @@ 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->pixels) { + munmap(xenfb->pixels, xenfb->fb_len); + xenfb->pixels = NULL; + } +} + + +static void xenfb_on_fb_event(struct xenfb *xenfb) { uint32_t prod, cons; struct xenfb_page *page = xenfb->fb.page; @@ -590,11 +594,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 */ @@ -602,7 +605,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; @@ -640,7 +643,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; @@ -662,9 +665,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); @@ -675,9 +677,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); @@ -688,9 +689,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); @@ -702,9 +702,9 @@ static int xenfb_send_position(struct xe } -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) @@ -719,9 +719,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; @@ -736,9 +736,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; @@ -794,12 +793,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->depth = fb_page->depth; + xenfb->width = fb_page->width; + xenfb->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->row_stride = fb_page->line_length; if (xenfb_map_fb(xenfb, domid) < 0) goto error; @@ -814,7 +813,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->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) @@ -827,19 +826,18 @@ int xenfb_attach_dom(struct xenfb *xenfb /* Register our keyboard & mouse handlers */ qemu_add_kbd_event_handler(xenfb_key_event, xenfb); qemu_add_mouse_event_handler(xenfb_mouse_event, xenfb, - xenfb_pub->abs_pointer_wanted, + xenfb->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->width, xenfb->height); return 0; @@ -898,11 +896,10 @@ static void xenfb_mouse_event(void *opaq { int i; struct xenfb *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); + dx * xenfb->ds->width / 0x7fff, + dy * xenfb->ds->height / 0x7fff); else xenfb_send_motion(xenfb, dx, dy); @@ -924,9 +921,9 @@ static void xenfb_mouse_event(void *opaq 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)); \ + 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) | \ @@ -945,40 +942,39 @@ static void xenfb_mouse_event(void *opaq */ 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 */ + if (xenfb->depth == xenfb->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), + memcpy(xenfb->ds->data + (line * xenfb->ds->linesize) + (x * xenfb->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) { + if (xenfb->ds->depth == 16) { BLT(uint8_t, uint16_t, 5, 2, 0, 11, 5, 0, 7, 7, 3); - } else if (ds->depth == 32) { + } else if (xenfb->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) { + if (xenfb->ds->depth == 8) { BLT(uint16_t, uint8_t, 11, 5, 0, 5, 2, 0, 31, 63, 31); - } else if (ds->depth == 32) { + } else if (xenfb->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) { + if (xenfb->ds->depth == 8) { BLT(uint32_t, uint8_t, 16, 8, 0, 5, 2, 0, 255, 255, 255); - } else if (ds->depth == 16) { + } else if (xenfb->ds->depth == 16) { BLT(uint32_t, uint16_t, 16, 8, 0, 11, 5, 0, 255, 255, 255); } } } - dpy_update(ds, x, y, w, h); + dpy_update(xenfb->ds, x, y, w, h); } /* QEMU display state changed, so refresh the framebuffer copy */ diff -r 58cc6fb7824c tools/ioemu/hw/xenfb.h --- a/tools/ioemu/hw/xenfb.h Tue Sep 11 11:53:35 2007 -0400 +++ b/tools/ioemu/hw/xenfb.h Tue Sep 11 11:55:15 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-Oct-24 20:42 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). The main difference from previous versions of this patch, is that at the suggestion of Markus Armbruster, I''vere-ordered the individual static functions so they are in order-of-call, rather than reversed. Although I now have to pre-declare them, it is much easier to read the code. I have also fixed the keycode -> keysym translations to match previous behaviour. xen_machine_pv.c | 9 xenfb.c | 721 +++++++++++++++++++++++++++++++------------------------ xenfb.h | 7 3 files changed, 415 insertions(+), 322 deletions(-) Signed-off-by: Daniel P. Berrange <berrange@redhat.com> diff -r bed4c2406f8b tools/ioemu/hw/xen_machine_pv.c --- a/tools/ioemu/hw/xen_machine_pv.c Tue Sep 11 11:55:15 2007 -0400 +++ b/tools/ioemu/hw/xen_machine_pv.c Tue Sep 11 11:56:11 2007 -0400 @@ -40,16 +40,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 bed4c2406f8b tools/ioemu/hw/xenfb.c --- a/tools/ioemu/hw/xenfb.c Tue Sep 11 11:55:15 2007 -0400 +++ b/tools/ioemu/hw/xenfb.c Tue Sep 11 11:56:11 2007 -0400 @@ -52,6 +52,20 @@ struct xenfb { char protocol[64]; /* frontend protocol */ }; +/* Functions for frontend/backend state machine*/ +static int xenfb_wait_for_frontend(struct xenfb_device *dev, IOHandler *handler); +static int xenfb_wait_for_backend(struct xenfb_device *dev, IOHandler *handler); +static void xenfb_backend_created_kbd(void *opaque); +static void xenfb_backend_created_fb(void *opaque); +static void xenfb_frontend_initialized_kbd(void *opaque); +static void xenfb_frontend_initialized_fb(void *opaque); +static void xenfb_frontend_connected_kbd(void *opaque); + +/* Helper functions for checking state of frontend/backend devices */ +static int xenfb_frontend_connected(struct xenfb_device *dev); +static int xenfb_frontend_initialized(struct xenfb_device *dev); +static int xenfb_backend_created(struct xenfb_device *dev); + /* Functions which tie the PVFB into the QEMU device model */ static void xenfb_key_event(void *opaque, int keycode); static void xenfb_mouse_event(void *opaque, @@ -60,6 +74,7 @@ static void xenfb_update(void *opaque); static void xenfb_update(void *opaque); static void xenfb_invalidate(void *opaque); static void xenfb_screen_dump(void *opaque, const char *name); +static int xenfb_register_console(struct xenfb *xenfb); /* * Tables to map from scancode to Linux input layer keycode. @@ -103,34 +118,6 @@ static const unsigned char atkbd_unxlate static unsigned char scancode2linux[512]; - -static void xenfb_detach_dom(struct xenfb *); - -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) @@ -193,27 +180,7 @@ static void xenfb_device_init(struct xen dev->xenfb = xenfb; } -static int xenfb_device_set_domain(struct xenfb_device *dev, int domid) -{ - dev->otherend_id = domid; - - 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(dev->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 *xenfb_new(int domid, DisplayState *ds) { struct xenfb *xenfb = qemu_malloc(sizeof(struct xenfb)); int serrno; @@ -246,35 +213,18 @@ struct xenfb *xenfb_new(void) if (!xenfb->xsh) goto fail; + fprintf(stderr, "FB: Waiting for KBD backend creation\n"); + xenfb_wait_for_backend(&xenfb->kbd, xenfb_backend_created_kbd); + return xenfb; fail: serrno = errno; - xenfb_delete(xenfb); + xenfb_shutdown(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) @@ -301,89 +251,12 @@ static int xenfb_switch_state(struct xen 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; } @@ -522,52 +395,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) { @@ -577,6 +404,24 @@ static void xenfb_detach_dom(struct xenf munmap(xenfb->pixels, xenfb->fb_len); xenfb->pixels = NULL; } +} + +/* Remove the backend area in xenbus since the framebuffer really is + going away. */ +void xenfb_shutdown(struct xenfb *xenfb) +{ + fprintf(stderr, "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); } @@ -643,6 +488,7 @@ static int xenfb_on_state_change(struct return 0; } +/* Send an event to the keyboard frontend driver */ static int xenfb_kbd_event(struct xenfb *xenfb, union xenkbd_in_event *event) { @@ -665,6 +511,7 @@ 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; @@ -677,6 +524,7 @@ 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; @@ -689,6 +537,7 @@ 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; @@ -701,24 +550,29 @@ static int xenfb_send_position(struct xe return xenfb_kbd_event(xenfb, &event); } - +/* 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); -} - + } +} + +/* Process ongoing events from the frontend devices */ static void xenfb_dispatch_store(void *opaque) { struct xenfb *xenfb = (struct xenfb *)opaque; @@ -731,124 +585,347 @@ static void xenfb_dispatch_store(void *o r = xenfb_on_state_change(&xenfb->fb); if (r == 0) r = xenfb_on_state_change(&xenfb->kbd); - if (r == -1) + if (r < 0) { + xenfb_shutdown(xenfb); exit(1); -} - - -int xenfb_attach_dom(struct xenfb *xenfb, int domid, DisplayState *ds) -{ - struct xs_handle *xsh = xenfb->xsh; - int val, serrno; + } +} + + +/**************************************************************** + * + * Functions for processing frontend config + * + ****************************************************************/ + + +/* 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->depth = fb_page->depth; - xenfb->width = fb_page->width; - xenfb->height = fb_page->height; - /* TODO check for consistency with the above */ - xenfb->fb_len = fb_page->mem_length; - xenfb->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) { + fprintf(stderr, "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->depth = fb_page->depth; + xenfb->width = fb_page->width; + xenfb->height = fb_page->height; + /* TODO check for consistency with the above */ + xenfb->fb_len = fb_page->mem_length; + xenfb->row_stride = fb_page->line_length; + fprintf(stderr, "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->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_key_event, xenfb); - qemu_add_mouse_event_handler(xenfb_mouse_event, xenfb, - xenfb->abs_pointer_wanted, - "Xen PVFB Mouse"); - - 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->width, xenfb->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; -} +} + + +/**************************************************************** + * + * Functions for frontend/backend state machine + * + ****************************************************************/ + +/* 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) +{ + fprintf(stderr, "Doing frontend watch on %s\n", dev->otherend); + if (!xs_watch(dev->xenfb->xsh, dev->otherend, "")) { + fprintf(stderr, "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) +{ + fprintf(stderr, "Doing backend watch on %s\n", dev->nodename); + if (!xs_watch(dev->xenfb->xsh, dev->nodename, "")) { + fprintf(stderr, "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; +} + +/* Callback invoked while waiting for KBD backend to change + * to the created state */ +static 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); + exit(1); + } + if (ret) + return; /* Still waiting */ + + if (xenfb_xs_printf(dev->xenfb->xsh, dev->nodename, "feature-abs-pointer", "1")) { + xenfb_shutdown(dev->xenfb); + exit(1); + } + + fprintf(stderr, "FB: Waiting for FB backend creation\n"); + xenfb_wait_for_backend(&dev->xenfb->fb, xenfb_backend_created_fb); +} + +/* Callback invoked while waiting for FB backend to change + * to the created state */ +static 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); + exit(1); + } + if (ret) + return; /* Still waiting */ + + fprintf(stderr, "FB: Waiting for KBD frontend initialization\n"); + xenfb_wait_for_frontend(&dev->xenfb->kbd, xenfb_frontend_initialized_kbd); +} + +/* Callback invoked while waiting for KBD frontend to change + * to the initialized state */ +static 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); + exit(1); + } + if (ret) + return; /* Still waiting */ + + + fprintf(stderr, "FB: Waiting for FB frontend initialization\n"); + xenfb_wait_for_frontend(&dev->xenfb->fb, xenfb_frontend_initialized_fb); +} + +/* Callback invoked while waiting for FB frontend to change + * to the initialized state */ +static 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); + exit(1); + } + if (ret) + return; /* Still waiting */ + + + if (xenfb_read_frontend_fb_config(dev->xenfb)) { + xenfb_shutdown(dev->xenfb); + exit(1); + } + + fprintf(stderr, "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 connected state */ +static 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); + exit(1); + } + if (ret) + return; /* Still waiting */ + + if (xenfb_read_frontend_kbd_config(dev->xenfb) < 0) { + xenfb_shutdown(dev->xenfb); + exit(1); + } + + xenfb_register_console(dev->xenfb); +} + + +/**************************************************************** + * + * Helper functions for checking state of frontend/backend devices + * + ****************************************************************/ + +/* 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) + return -1; + free(vec); + + state = xenfb_read_state(dev->xenfb->xsh, dev->otherend); + if (!((1 <<state) & ((1 << XenbusStateUnknown) | + (1 << XenbusStateConnected)))) { + fprintf(stderr, "FB: Carry on waiting\n"); + return 1; + } + + /* Don''t unwatch frontend - we need to detect shutdown */ + /*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) + 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 + ))) { + fprintf(stderr, "FB: Carry on waiting\n"); + return 1; + } + + xs_unwatch(dev->xenfb->xsh, dev->otherend, ""); + + switch (state) { +#if 1 + case XenbusStateConnected: + printf("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 */ +static 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) + 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 + ))) { + fprintf(stderr, "FB: Carry on waiting\n"); + return 1; + } + + xs_unwatch(dev->xenfb->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: + fprintf(stderr, "Wrong state %d\n", state); + return -1; + } + xenfb_switch_state(dev, XenbusStateInitWait); + if (xenfb_hotplug(dev) < 0) + return -1; + + return 0; +} + + +/**************************************************************** + * + * QEMU device model integration functions + * + ****************************************************************/ /* * Send a key event from the client to the guest OS @@ -996,6 +1073,32 @@ static void xenfb_screen_dump(void *opaq static void xenfb_screen_dump(void *opaque, const char *name) { } +/* Register a QEMU graphical console, and key/mouse handler, + * connecting up their events to the frontend */ +static int xenfb_register_console(struct xenfb *xenfb) { + /* Register our keyboard & mouse handlers */ + qemu_add_kbd_event_handler(xenfb_key_event, xenfb); + qemu_add_mouse_event_handler(xenfb_mouse_event, xenfb, + xenfb->abs_pointer_wanted, + "Xen PVFB Mouse"); + + /* Tell QEMU to allocate a graphical console */ + graphic_console_init(xenfb->ds, + xenfb_update, + xenfb_invalidate, + xenfb_screen_dump, + xenfb); + dpy_resize(xenfb->ds, xenfb->width, xenfb->height); + + if (qemu_set_fd_handler2(xenfb->evt_xch, NULL, xenfb_dispatch_channel, NULL, xenfb) < 0) + return -1; + if (qemu_set_fd_handler2(xs_fileno(xenfb->xsh), NULL, xenfb_dispatch_store, NULL, xenfb) < 0) + return -1; + + fprintf(stderr, "Xen Framebuffer registered\n"); + return 0; +} + /* * Local variables: * c-indent-level: 8 diff -r bed4c2406f8b tools/ioemu/hw/xenfb.h --- a/tools/ioemu/hw/xenfb.h Tue Sep 11 11:55:15 2007 -0400 +++ b/tools/ioemu/hw/xenfb.h Tue Sep 11 11:56:11 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-Oct-24 20:43 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 | 432 ++++++++++++++++++++++++++++++++ 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 tools/python/xen/xend/XendDomainInfo.py | 7 6 files changed, 471 insertions(+), 5 deletions(-) Signed-off-by: Daniel P. Berrange <berrange@redhat.com> diff -r 96aa5e956a9f tools/ioemu/Makefile.target --- a/tools/ioemu/Makefile.target Wed Oct 24 15:25:24 2007 -0400 +++ b/tools/ioemu/Makefile.target Wed Oct 24 15:25:27 2007 -0400 @@ -412,6 +412,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 96aa5e956a9f tools/ioemu/hw/xen_console.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/ioemu/hw/xen_console.c Wed Oct 24 15:30:41 2007 -0400 @@ -0,0 +1,432 @@ +/* + * 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 <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 <xs.h> +#include <xen/io/console.h> +#include <xenctrl.h> + +#include "vl.h" + +#include "xen_console.h" + +#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 */ + if (!(xs_watch(dom->xsh, dom->conspath, ""))) { + fprintf(stderr, "Unable to watch console %s\n", dom->conspath); + goto fail; + } + if (!(xs_watch(dom->xsh, dom->serialpath, ""))) { + fprintf(stderr, "Unable to watch console %s\n", dom->conspath); + xs_unwatch(dom->xsh, dom->conspath, ""); + goto fail; + } + 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; + +fail: + xs_daemon_close(dom->xsh); + free(dom->serialpath); + free(dom->conspath); + free(dom); + return -1; +} + + +/* + * Local variables: + * c-file-style: "linux" + * indent-tabs-mode: t + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff -r 96aa5e956a9f tools/ioemu/hw/xen_console.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/ioemu/hw/xen_console.h Wed Oct 24 15:25:27 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 96aa5e956a9f tools/ioemu/hw/xen_machine_pv.c --- a/tools/ioemu/hw/xen_machine_pv.c Wed Oct 24 15:25:24 2007 -0400 +++ b/tools/ioemu/hw/xen_machine_pv.c Wed Oct 24 15:25:27 2007 -0400 @@ -23,6 +23,7 @@ */ #include "vl.h" +#include "xen_console.h" #include "xenfb.h" /* The Xen PV machine currently provides @@ -38,6 +39,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 96aa5e956a9f tools/ioemu/xenstore.c --- a/tools/ioemu/xenstore.c Wed Oct 24 15:25:24 2007 -0400 +++ b/tools/ioemu/xenstore.c Wed Oct 24 15:25:27 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; diff -r 96aa5e956a9f tools/python/xen/xend/XendDomainInfo.py --- a/tools/python/xen/xend/XendDomainInfo.py Wed Oct 24 15:25:24 2007 -0400 +++ b/tools/python/xen/xend/XendDomainInfo.py Wed Oct 24 15:30:26 2007 -0400 @@ -1761,10 +1761,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() -- |=- 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-Oct-24 20:44 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 | 23 +-- image.py | 382 ++++++++++++++++++++++++++++-------------------------- server/vfbif.py | 108 ++------------- 5 files changed, 251 insertions(+), 302 deletions(-) Signed-off-by: Daniel P. Berrange <berrange@redhat.com> diff -r f0a3bb81fbe3 tools/python/xen/xend/XendCheckpoint.py --- a/tools/python/xen/xend/XendCheckpoint.py Wed Oct 24 15:31:33 2007 -0400 +++ b/tools/python/xen/xend/XendCheckpoint.py Wed Oct 24 15:57:32 2007 -0400 @@ -6,6 +6,7 @@ # this archive for more details. import os +import os.path import re import string import threading @@ -108,7 +109,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) @@ -245,6 +246,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 f0a3bb81fbe3 tools/python/xen/xend/XendConfig.py --- a/tools/python/xen/xend/XendConfig.py Wed Oct 24 15:31:33 2007 -0400 +++ b/tools/python/xen/xend/XendConfig.py Wed Oct 24 15:31:35 2007 -0400 @@ -32,6 +32,7 @@ from xen.xend.server.netif import random from xen.xend.server.netif import randomMAC from xen.util.blkif import blkdev_name_to_number from xen.util import xsconstants +import xen.util.auxbin log = logging.getLogger("xend.XendConfig") log.setLevel(logging.WARN) @@ -233,8 +234,6 @@ LEGACY_XENSTORE_VM_PARAMS = [ ''on_xend_start'', ''on_xend_stop'', ] - -DEFAULT_DM = ''/usr/lib/xen/bin/qemu-dm'' ## ## Config Choices @@ -393,13 +392,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''): @@ -744,16 +744,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''] dev_config.append([''type'', ''vnc'']) # copy VNC related params from platform config to vfb dev conf @@ -764,6 +755,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 f0a3bb81fbe3 tools/python/xen/xend/XendDomainInfo.py --- a/tools/python/xen/xend/XendDomainInfo.py Wed Oct 24 15:31:33 2007 -0400 +++ b/tools/python/xen/xend/XendDomainInfo.py Wed Oct 24 15:58:37 2007 -0400 @@ -1455,10 +1455,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): @@ -1709,11 +1715,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: @@ -1881,8 +1882,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 f0a3bb81fbe3 tools/python/xen/xend/image.py --- a/tools/python/xen/xend/image.py Wed Oct 24 15:31:33 2007 -0400 +++ b/tools/python/xen/xend/image.py Wed Oct 24 15:54:42 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): @@ -229,6 +357,19 @@ class LinuxImageHandler(ImageHandler): flags = self.flags, vhpt = self.vhpt) + 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" @@ -262,15 +403,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)), @@ -278,49 +410,18 @@ class HVMImageHandler(ImageHandler): ("image/display", self.display)) self.vm.storeVm(("rtc/timeoffset", rtc_timeoffset)) - self.pid = None - 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("acpi = %d", self.acpi) - log.debug("apic = %d", self.apic) - - rc = xc.hvm_build(domid = self.vm.getDomid(), - image = self.kernel, - memsize = mem_mb, - vcpus = self.vm.getVCpuCount(), - acpi = self.acpi, - apic = self.apic) - - rc[''notes''] = { ''SUSPEND_CANCEL'': 1 } - - rc[''store_mfn''] = xc.hvm_get_param(self.vm.getDomid(), - HVM_PARAM_STORE_PFN) - xc.hvm_set_param(self.vm.getDomid(), HVM_PARAM_STORE_EVTCHN, - store_evtchn) - - 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'', ''pci'' ] - - ret = [''-vcpus'', str(self.vm.getVCpuCount())] + ''acpi'', ''usb'', ''usbdevice'', ''pci'' ] for a in dmargs: v = vmConfig[''platform''].get(a) @@ -349,7 +450,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'']: @@ -378,130 +478,43 @@ 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("acpi = %d", self.acpi) + log.debug("apic = %d", self.apic) + + rc = xc.hvm_build(domid = self.vm.getDomid(), + image = self.kernel, + memsize = mem_mb, + vcpus = self.vm.getVCpuCount(), + acpi = self.acpi, + apic = self.apic) + rc[''notes''] = { ''SUSPEND_CANCEL'': 1 } + + rc[''store_mfn''] = xc.hvm_get_param(self.vm.getDomid(), + HVM_PARAM_STORE_PFN) + xc.hvm_set_param(self.vm.getDomid(), HVM_PARAM_STORE_EVTCHN, + store_evtchn) + + return rc class IA64_HVM_ImageHandler(HVMImageHandler): @@ -528,6 +541,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 IA64_Linux_ImageHandler(LinuxImageHandler): diff -r f0a3bb81fbe3 tools/python/xen/xend/server/vfbif.py --- a/tools/python/xen/xend/server/vfbif.py Wed Oct 24 15:31:33 2007 -0400 +++ b/tools/python/xen/xend/server/vfbif.py Wed Oct 24 15:56:36 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,19 +51,16 @@ 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 +74,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-Oct-24 20:44 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> diff -r b090544a03f1 tools/console/daemon/io.c --- a/tools/console/daemon/io.c Wed Oct 24 15:31:35 2007 -0400 +++ b/tools/console/daemon/io.c Wed Oct 24 15:37:24 2007 -0400 @@ -377,6 +377,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, @@ -393,6 +394,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 b090544a03f1 tools/python/xen/xend/XendDomainInfo.py --- a/tools/python/xen/xend/XendDomainInfo.py Wed Oct 24 15:31:35 2007 -0400 +++ b/tools/python/xen/xend/XendDomainInfo.py Wed Oct 24 15:37:24 2007 -0400 @@ -916,8 +916,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
Alex Williamson
2007-Oct-25 18:56 UTC
Re: [Xen-devel] PATCH 0/10: Merge PV framebuffer & console into QEMU
On Wed, 2007-10-24 at 21:35 +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.Hi Dan, Does anything change with respect to specifying a vfb= option with this series? On ia64, the guest xenbus never seems to find the device it''s looking for: NET: Registered protocol family 1 NET: Registered protocol family 17 Bridge firewalling registered xen privcmd uses pseudo physical addr range [0x100000000, 0x3ffff000000] (4190192MB) Xen p2m: assign p2m table of [0x0000000000000000, 0x0000000100004000) Xen p2m: to [0x0000000100000000, 0x0000000104000000) (65536 KBytes) XENBUS: Waiting for devices to initialise: 295s...290s...285s...280s...275s...270s...265s...260s...255s...250s...245s... I do have a qemu process running for this domain: /usr/lib/xen/bin/qemu-dm -d 7 -domain-name debian -vnc 0.0.0.0:0 -serial pty -M xenpv Seems like the async hookup isn''t happening. Anything obvious to check? I confirmed I do still have vfb on ia64 with a tools build from the cset before this series. Thanks, Alex -- Alex Williamson HP Open Source & Linux Org. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel P. Berrange
2007-Oct-25 19:02 UTC
Re: [Xen-devel] PATCH 0/10: Merge PV framebuffer & console into QEMU
On Thu, Oct 25, 2007 at 12:56:35PM -0600, Alex Williamson wrote:> > On Wed, 2007-10-24 at 21:35 +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. > > Hi Dan, > > Does anything change with respect to specifying a vfb= option with > this series? On ia64, the guest xenbus never seems to find the device > it''s looking for:The configuration doesn''t change, but now QEMU is responsible for being the backend instead of xen-vncfb. The /var/log/xen/qemu-dm-<domid>.log file will print out a message for each of the xenbus state transitiions the QEMU backend goes through when connecting to the frontend PVFB.> > NET: Registered protocol family 1 > NET: Registered protocol family 17 > Bridge firewalling registered > xen privcmd uses pseudo physical addr range [0x100000000, 0x3ffff000000] > (4190192MB) > Xen p2m: assign p2m table of [0x0000000000000000, 0x0000000100004000) > Xen p2m: to [0x0000000100000000, 0x0000000104000000) (65536 KBytes) > XENBUS: Waiting for devices to initialise: > 295s...290s...285s...280s...275s...270s...265s...260s...255s...250s...245s... > > I do have a qemu process running for this domain: > > /usr/lib/xen/bin/qemu-dm -d 7 -domain-name debian -vnc 0.0.0.0:0 -serial pty -M xenpvThat''s looking correct.> Seems like the async hookup isn''t happening. Anything obvious to check? > I confirmed I do still have vfb on ia64 with a tools build from the cset > before this series. Thanks,The QEMU logfile is the best place to look. And compare what state it is in, with the info in xenstore associated with the front/back ends. If you wnat any help, mail me the output of ''xenstore-ls'' and the QEMU logfile and I can see if anything obvious is wrong. 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-Oct-25 21:23 UTC
Re: [Xen-devel] PATCH 0/10: Merge PV framebuffer & console into QEMU
On Thu, Oct 25, 2007 at 12:56:35PM -0600, Alex Williamson wrote:> > On Wed, 2007-10-24 at 21:35 +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.[snip]> Seems like the async hookup isn''t happening. Anything obvious to check? > I confirmed I do still have vfb on ia64 with a tools build from the cset > before this series. Thanks,Another thing worth testing, is to try a build at 16225:695871933840 vs 16226:695871933840. 16226 contains a refactoring of the front/back handshake code, so if it still works on 16225 then it points to a bug in the state machine changes I did. 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
Alex Williamson
2007-Oct-25 21:41 UTC
Re: [Xen-devel] PATCH 0/10: Merge PV framebuffer & console into QEMU
On Thu, 2007-10-25 at 22:23 +0100, Daniel P. Berrange wrote:> > Seems like the async hookup isn''t happening. Anything obvious to check? > > I confirmed I do still have vfb on ia64 with a tools build from the cset > > before this series. Thanks, > > Another thing worth testing, is to try a build at 16225:695871933840 > vs 16226:695871933840. 16226 contains a refactoring of the front/back > handshake code, so if it still works on 16225 then it points to a bug > in the state machine changes I did.Yes, that is the case. 16225 works fine. On 16226, the domu hangs, then gives me a vkbd error: Error: Device 0 (vkbd) could not be connected. Hotplug scripts not working. Here''s was I see in the qmeu log file: xs_read(): vncpasswd get error. /vm/c766b61d-58e1-8efe-b853-40addbd451ae/vncpasswd. shift keysym 003e keycode 86 shift keysym 00a6 keycode 86 keypad keysym ffae keycode 83 keypad keysym ffac keycode 83 ... shift keysym 0021 keycode 2 shift keysym 0040 keycode 3 shift keysym 0023 keycode 4 ... shift keysym 003f keycode 53 FB: Waiting for KBD backend creation Doing backend watch on Watch for dev failed The same failure happens in the qmeu log with tip. It seems odd to me that xenfb_new() can return failure, but we don''t make use of the return value from xenfb_wait_for_backend(). I also attached the xenstore-ls output. This was domid 5 for this latest attempt on cset 16226. Thanks, Alex -- Alex Williamson HP Open Source & Linux Org. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Markus Armbruster
2007-Oct-26 08:16 UTC
Re: [Xen-devel] PATCH 0/10: Merge PV framebuffer & console into QEMU
Hrrrm, diagnostics omit errno. Alex, could you retry with the appended (obvious, but untested) patch applied? --- tools/ioemu/hw/xenfb.c~ 2007-10-26 10:04:43.000000000 +0200 +++ tools/ioemu/hw/xenfb.c 2007-10-26 10:11:09.000000000 +0200 @@ -664,7 +664,8 @@ { fprintf(stderr, "Doing frontend watch on %s\n", dev->otherend); if (!xs_watch(dev->xenfb->xsh, dev->otherend, "")) { - fprintf(stderr, "Watch for dev failed\n"); + fprintf(stderr, "Watch for dev failed (%s)\n", + strerror(errno)); return -1; } @@ -680,7 +681,8 @@ { fprintf(stderr, "Doing backend watch on %s\n", dev->nodename); if (!xs_watch(dev->xenfb->xsh, dev->nodename, "")) { - fprintf(stderr, "Watch for dev failed\n"); + fprintf(stderr, "Watch for dev failed (%s)\n", + strerror(errno)); return -1; } _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel P. Berrange
2007-Oct-26 16:15 UTC
Re: [Xen-devel] PATCH 0/10: Merge PV framebuffer & console into QEMU
On Thu, Oct 25, 2007 at 03:41:22PM -0600, Alex Williamson wrote:> > On Thu, 2007-10-25 at 22:23 +0100, Daniel P. Berrange wrote: > > > Seems like the async hookup isn''t happening. Anything obvious to check? > > > I confirmed I do still have vfb on ia64 with a tools build from the cset > > > before this series. Thanks, > > > > Another thing worth testing, is to try a build at 16225:695871933840 > > vs 16226:695871933840. 16226 contains a refactoring of the front/back > > handshake code, so if it still works on 16225 then it points to a bug > > in the state machine changes I did. > > Yes, that is the case. 16225 works fine. On 16226, the domu hangs, > then gives me a vkbd error: > > Error: Device 0 (vkbd) could not be connected. Hotplug scripts not > working. > > Here''s was I see in the qmeu log file: > > xs_read(): vncpasswd get > error. /vm/c766b61d-58e1-8efe-b853-40addbd451ae/vncpasswd. > shift keysym 003e keycode 86 > shift keysym 00a6 keycode 86 > keypad keysym ffae keycode 83 > keypad keysym ffac keycode 83 > ... > shift keysym 0021 keycode 2 > shift keysym 0040 keycode 3 > shift keysym 0023 keycode 4 > ... > shift keysym 003f keycode 53 > FB: Waiting for KBD backend creation > Doing backend watch onThis was the useful line ^^^^ there should have been a xenstore device path there, but I lost the hunk of a patch which initialized this. I just sent a patch to the list which will fix this. It wasn''t ia64 specific. 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