Daniel P. Berrange
2007-Aug-15 20:00 UTC
[Xen-devel] PATCH: 0/10: Merge xenfb & xenconsoled into qemu-dm
The following series of 10 patches is a merge of the xenfb and xenconsoled functionality into the qemu-dm code. The general approach taken is to have qemu-dm provide two machine types - one for xen paravirt, the other for fullyvirt. For compatability the later is the default. The goals overall are to kill LibVNCServer, remove alot of code duplication and/or parallel impls of the same concepts, and increase the functionality for PV. In particular this will let paravirt guests take advantage of TLS encryption for the VNC server, and let us configure the text console in all the variety of ways QEMU supports (PTY, File, TCP, TCP_Telnet,UDP, etc). One interesting possiblity that merging the text & graphics consoles into same daemon allows for, is to expose the pygrub screens over both a PTY and VNC server at the same time. If I can figure out how to actually code this idea it would solve a major headache when using bootloaders with PV guests remotely. The only feature this re-factoring looses is the ability to have the paravirt text console persistently logged to a file. QEMU allows us to specify that a character device is either sent to a PTY, or a file, but not both at the same time. I''m thinking about ways in which QEMU''s character device config syntax & drivers may be extended to allow use of a PTY & File concurrently. The patches should be applied in order - after each individual patch you should still have a fully operational system for both FV & PV. 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
Daniel P. Berrange
2007-Aug-15 20:02 UTC
Re: [Xen-devel] PATCH: 1/10: Add a QEMU machine type for fullvirt guests
This patch does a (no functional change) re-arrangement of the code for starting up a fully virtualized guest. In particular it creates a new QEMU machine type for Xen fullyvirt guests which can be specified with ''-M xenfv''. For compatability this is in fact made to be the default. The code for setting up memory maps is moved out of vl.c, and into hw/xen_machine_fv.c. This is basically to ensure that it can be easily skipped when we add a paravirt machine type in the next patch. b/tools/ioemu/hw/xen_machine_fv.c | 286 ++++++++++++++++++++++++++++++++++++++ tools/ioemu/Makefile.target | 1 tools/ioemu/vl.c | 244 -------------------------------- tools/ioemu/vl.h | 3 4 files changed, 295 insertions(+), 239 deletions(-) Signed-off-by: Daniel P. Berrange <berrange@redhat.com> Dan. diff -r 7953164cebb6 tools/ioemu/Makefile.target --- a/tools/ioemu/Makefile.target Tue Aug 07 09:07:29 2007 +0100 +++ b/tools/ioemu/Makefile.target Wed Aug 15 14:14:55 2007 -0400 @@ -400,6 +400,7 @@ VL_OBJS+= piix4acpi.o VL_OBJS+= piix4acpi.o VL_OBJS+= xenstore.o VL_OBJS+= xen_platform.o +VL_OBJS+= xen_machine_fv.o VL_OBJS+= tpm_tis.o CPPFLAGS += -DHAS_AUDIO endif diff -r 7953164cebb6 tools/ioemu/hw/xen_machine_fv.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/ioemu/hw/xen_machine_fv.c Wed Aug 15 14:15:25 2007 -0400 @@ -0,0 +1,286 @@ +/* + * QEMU Xen FV Machine + * + * Copyright (c) 2003-2007 Fabrice Bellard + * Copyright (c) 2007 Red Hat + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "vl.h" +#include <xen/hvm/params.h> +#include <sys/mman.h> + +#if defined(MAPCACHE) + +#if defined(__i386__) +#define MAX_MCACHE_SIZE 0x40000000 /* 1GB max for x86 */ +#define MCACHE_BUCKET_SHIFT 16 +#elif defined(__x86_64__) +#define MAX_MCACHE_SIZE 0x1000000000 /* 64GB max for x86_64 */ +#define MCACHE_BUCKET_SHIFT 20 +#endif + +#define MCACHE_BUCKET_SIZE (1UL << MCACHE_BUCKET_SHIFT) + +#define BITS_PER_LONG (sizeof(long)*8) +#define BITS_TO_LONGS(bits) \ + (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG) +#define DECLARE_BITMAP(name,bits) \ + unsigned long name[BITS_TO_LONGS(bits)] +#define test_bit(bit,map) \ + (!!((map)[(bit)/BITS_PER_LONG] & (1UL << ((bit)%BITS_PER_LONG)))) + +struct map_cache { + unsigned long paddr_index; + uint8_t *vaddr_base; + DECLARE_BITMAP(valid_mapping, MCACHE_BUCKET_SIZE>>PAGE_SHIFT); +}; + +static struct map_cache *mapcache_entry; +static unsigned long nr_buckets; + +/* For most cases (>99.9%), the page address is the same. */ +static unsigned long last_address_index = ~0UL; +static uint8_t *last_address_vaddr; + +static int qemu_map_cache_init(void) +{ + unsigned long size; + + nr_buckets = (((MAX_MCACHE_SIZE >> PAGE_SHIFT) + + (1UL << (MCACHE_BUCKET_SHIFT - PAGE_SHIFT)) - 1) >> + (MCACHE_BUCKET_SHIFT - PAGE_SHIFT)); + fprintf(logfile, "qemu_map_cache_init nr_buckets = %lx\n", nr_buckets); + + /* + * Use mmap() directly: lets us allocate a big hash table with no up-front + * cost in storage space. The OS will allocate memory only for the buckets + * that we actually use. All others will contain all zeroes. + */ + size = nr_buckets * sizeof(struct map_cache); + size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); + mapcache_entry = mmap(NULL, size, PROT_READ|PROT_WRITE, + MAP_SHARED|MAP_ANONYMOUS, 0, 0); + if (mapcache_entry == MAP_FAILED) { + errno = ENOMEM; + return -1; + } + + return 0; +} + +static void qemu_remap_bucket(struct map_cache *entry, + unsigned long address_index) +{ + uint8_t *vaddr_base; + unsigned long pfns[MCACHE_BUCKET_SIZE >> PAGE_SHIFT]; + unsigned int i, j; + + if (entry->vaddr_base != NULL) { + errno = munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE); + if (errno) { + fprintf(logfile, "unmap fails %d\n", errno); + exit(-1); + } + } + + for (i = 0; i < MCACHE_BUCKET_SIZE >> PAGE_SHIFT; i++) + pfns[i] = (address_index << (MCACHE_BUCKET_SHIFT-PAGE_SHIFT)) + i; + + vaddr_base = xc_map_foreign_batch(xc_handle, domid, PROT_READ|PROT_WRITE, + pfns, MCACHE_BUCKET_SIZE >> PAGE_SHIFT); + if (vaddr_base == NULL) { + fprintf(logfile, "xc_map_foreign_batch error %d\n", errno); + exit(-1); + } + + entry->vaddr_base = vaddr_base; + entry->paddr_index = address_index; + + for (i = 0; i < MCACHE_BUCKET_SIZE >> PAGE_SHIFT; i += BITS_PER_LONG) { + unsigned long word = 0; + j = ((i + BITS_PER_LONG) > (MCACHE_BUCKET_SIZE >> PAGE_SHIFT)) ? + (MCACHE_BUCKET_SIZE >> PAGE_SHIFT) % BITS_PER_LONG : BITS_PER_LONG; + while (j > 0) + word = (word << 1) | !(pfns[i + --j] & 0xF0000000UL); + entry->valid_mapping[i / BITS_PER_LONG] = word; + } +} + +uint8_t *qemu_map_cache(target_phys_addr_t phys_addr) +{ + struct map_cache *entry; + unsigned long address_index = phys_addr >> MCACHE_BUCKET_SHIFT; + unsigned long address_offset = phys_addr & (MCACHE_BUCKET_SIZE-1); + + if (address_index == last_address_index) + return last_address_vaddr + address_offset; + + entry = &mapcache_entry[address_index % nr_buckets]; + + if (entry->vaddr_base == NULL || entry->paddr_index != address_index || + !test_bit(address_offset>>PAGE_SHIFT, entry->valid_mapping)) + qemu_remap_bucket(entry, address_index); + + if (!test_bit(address_offset>>PAGE_SHIFT, entry->valid_mapping)) + return NULL; + + last_address_index = address_index; + last_address_vaddr = entry->vaddr_base; + + return last_address_vaddr + address_offset; +} + +void qemu_invalidate_map_cache(void) +{ + unsigned long i; + + mapcache_lock(); + + for (i = 0; i < nr_buckets; i++) { + struct map_cache *entry = &mapcache_entry[i]; + + if (entry->vaddr_base == NULL) + continue; + + errno = munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE); + if (errno) { + fprintf(logfile, "unmap fails %d\n", errno); + exit(-1); + } + + entry->paddr_index = 0; + entry->vaddr_base = NULL; + } + + last_address_index = ~0UL; + last_address_vaddr = NULL; + + mapcache_unlock(); +} + +#endif /* defined(MAPCACHE) */ + + +static void xen_init_fv(uint64_t ram_size, int vga_ram_size, char *boot_device, + DisplayState *ds, const char **fd_filename, + int snapshot, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename) +{ + unsigned long ioreq_pfn; + extern void *shared_page; + extern void *buffered_io_page; +#ifdef __ia64__ + unsigned long nr_pages; + xen_pfn_t *page_array; + extern void *buffered_pio_page; +#endif + +#if defined(__i386__) || defined(__x86_64__) + + if (qemu_map_cache_init()) { + fprintf(logfile, "qemu_map_cache_init returned: error %d\n", errno); + exit(-1); + } + + xc_get_hvm_param(xc_handle, domid, HVM_PARAM_IOREQ_PFN, &ioreq_pfn); + fprintf(logfile, "shared page at pfn %lx\n", ioreq_pfn); + shared_page = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, + PROT_READ|PROT_WRITE, ioreq_pfn); + if (shared_page == NULL) { + fprintf(logfile, "map shared IO page returned error %d\n", errno); + exit(-1); + } + + xc_get_hvm_param(xc_handle, domid, HVM_PARAM_BUFIOREQ_PFN, &ioreq_pfn); + fprintf(logfile, "buffered io page at pfn %lx\n", ioreq_pfn); + buffered_io_page = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, + PROT_READ|PROT_WRITE, ioreq_pfn); + if (buffered_io_page == NULL) { + fprintf(logfile, "map buffered IO page returned error %d\n", errno); + exit(-1); + } + +#elif defined(__ia64__) + + nr_pages = ram_size/PAGE_SIZE; + + page_array = (xen_pfn_t *)malloc(nr_pages * sizeof(xen_pfn_t)); + if (page_array == NULL) { + fprintf(logfile, "malloc returned error %d\n", errno); + exit(-1); + } + + shared_page = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, + PROT_READ|PROT_WRITE, + IO_PAGE_START >> PAGE_SHIFT); + + buffered_io_page =xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, + PROT_READ|PROT_WRITE, + BUFFER_IO_PAGE_START >> PAGE_SHIFT); + + buffered_pio_page = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, + PROT_READ|PROT_WRITE, + BUFFER_PIO_PAGE_START >> PAGE_SHIFT); + + for (i = 0; i < nr_pages; i++) + page_array[i] = i; + + /* VTI will not use memory between 3G~4G, so we just pass a legal pfn + to make QEMU map continuous virtual memory space */ + if (ram_size > MMIO_START) { + for (i = 0 ; i < (MEM_G >> PAGE_SHIFT); i++) + page_array[(MMIO_START >> PAGE_SHIFT) + i] + (STORE_PAGE_START >> PAGE_SHIFT); + } + + phys_ram_base = xc_map_foreign_batch(xc_handle, domid, + PROT_READ|PROT_WRITE, + page_array, nr_pages); + if (phys_ram_base == 0) { + fprintf(logfile, "xc_map_foreign_batch returned error %d\n", errno); + exit(-1); + } + free(page_array); +#endif + + timeoffset_get(); + + + pc_machine.init(ram_size, vga_ram_size, boot_device, ds, fd_filename, + snapshot, kernel_filename, kernel_cmdline, initrd_filename); +} + +QEMUMachine xenfv_machine = { + "xenfv", + "Xen Fully-virtualized PC", + xen_init_fv, +}; + +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -r 7953164cebb6 tools/ioemu/vl.c --- a/tools/ioemu/vl.c Tue Aug 07 09:07:29 2007 +0100 +++ b/tools/ioemu/vl.c Wed Aug 15 14:16:53 2007 -0400 @@ -89,7 +89,6 @@ #include "exec-all.h" -#include <xen/hvm/params.h> #define DEFAULT_NETWORK_SCRIPT "/etc/xen/qemu-ifup" #define DEFAULT_BRIDGE "xenbr0" #ifdef __sun__ @@ -6647,8 +6646,12 @@ void register_machines(void) void register_machines(void) { #if defined(TARGET_I386) +#ifndef CONFIG_DM qemu_register_machine(&pc_machine); qemu_register_machine(&isapc_machine); +#else + qemu_register_machine(&xenfv_machine); +#endif #elif defined(TARGET_PPC) qemu_register_machine(&heathrow_machine); qemu_register_machine(&core99_machine); @@ -6856,156 +6859,6 @@ int set_mm_mapping(int xc_handle, uint32 return 0; } -#if defined(MAPCACHE) - -#if defined(__i386__) -#define MAX_MCACHE_SIZE 0x40000000 /* 1GB max for x86 */ -#define MCACHE_BUCKET_SHIFT 16 -#elif defined(__x86_64__) -#define MAX_MCACHE_SIZE 0x1000000000 /* 64GB max for x86_64 */ -#define MCACHE_BUCKET_SHIFT 20 -#endif - -#define MCACHE_BUCKET_SIZE (1UL << MCACHE_BUCKET_SHIFT) - -#define BITS_PER_LONG (sizeof(long)*8) -#define BITS_TO_LONGS(bits) \ - (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG) -#define DECLARE_BITMAP(name,bits) \ - unsigned long name[BITS_TO_LONGS(bits)] -#define test_bit(bit,map) \ - (!!((map)[(bit)/BITS_PER_LONG] & (1UL << ((bit)%BITS_PER_LONG)))) - -struct map_cache { - unsigned long paddr_index; - uint8_t *vaddr_base; - DECLARE_BITMAP(valid_mapping, MCACHE_BUCKET_SIZE>>PAGE_SHIFT); -}; - -static struct map_cache *mapcache_entry; -static unsigned long nr_buckets; - -/* For most cases (>99.9%), the page address is the same. */ -static unsigned long last_address_index = ~0UL; -static uint8_t *last_address_vaddr; - -static int qemu_map_cache_init(void) -{ - unsigned long size; - - nr_buckets = (((MAX_MCACHE_SIZE >> PAGE_SHIFT) + - (1UL << (MCACHE_BUCKET_SHIFT - PAGE_SHIFT)) - 1) >> - (MCACHE_BUCKET_SHIFT - PAGE_SHIFT)); - fprintf(logfile, "qemu_map_cache_init nr_buckets = %lx\n", nr_buckets); - - /* - * Use mmap() directly: lets us allocate a big hash table with no up-front - * cost in storage space. The OS will allocate memory only for the buckets - * that we actually use. All others will contain all zeroes. - */ - size = nr_buckets * sizeof(struct map_cache); - size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); - mapcache_entry = mmap(NULL, size, PROT_READ|PROT_WRITE, - MAP_SHARED|MAP_ANONYMOUS, 0, 0); - if (mapcache_entry == MAP_FAILED) { - errno = ENOMEM; - return -1; - } - - return 0; -} - -static void qemu_remap_bucket(struct map_cache *entry, - unsigned long address_index) -{ - uint8_t *vaddr_base; - unsigned long pfns[MCACHE_BUCKET_SIZE >> PAGE_SHIFT]; - unsigned int i, j; - - if (entry->vaddr_base != NULL) { - errno = munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE); - if (errno) { - fprintf(logfile, "unmap fails %d\n", errno); - exit(-1); - } - } - - for (i = 0; i < MCACHE_BUCKET_SIZE >> PAGE_SHIFT; i++) - pfns[i] = (address_index << (MCACHE_BUCKET_SHIFT-PAGE_SHIFT)) + i; - - vaddr_base = xc_map_foreign_batch(xc_handle, domid, PROT_READ|PROT_WRITE, - pfns, MCACHE_BUCKET_SIZE >> PAGE_SHIFT); - if (vaddr_base == NULL) { - fprintf(logfile, "xc_map_foreign_batch error %d\n", errno); - exit(-1); - } - - entry->vaddr_base = vaddr_base; - entry->paddr_index = address_index; - - for (i = 0; i < MCACHE_BUCKET_SIZE >> PAGE_SHIFT; i += BITS_PER_LONG) { - unsigned long word = 0; - j = ((i + BITS_PER_LONG) > (MCACHE_BUCKET_SIZE >> PAGE_SHIFT)) ? - (MCACHE_BUCKET_SIZE >> PAGE_SHIFT) % BITS_PER_LONG : BITS_PER_LONG; - while (j > 0) - word = (word << 1) | !(pfns[i + --j] & 0xF0000000UL); - entry->valid_mapping[i / BITS_PER_LONG] = word; - } -} - -uint8_t *qemu_map_cache(target_phys_addr_t phys_addr) -{ - struct map_cache *entry; - unsigned long address_index = phys_addr >> MCACHE_BUCKET_SHIFT; - unsigned long address_offset = phys_addr & (MCACHE_BUCKET_SIZE-1); - - if (address_index == last_address_index) - return last_address_vaddr + address_offset; - - entry = &mapcache_entry[address_index % nr_buckets]; - - if (entry->vaddr_base == NULL || entry->paddr_index != address_index || - !test_bit(address_offset>>PAGE_SHIFT, entry->valid_mapping)) - qemu_remap_bucket(entry, address_index); - - if (!test_bit(address_offset>>PAGE_SHIFT, entry->valid_mapping)) - return NULL; - - last_address_index = address_index; - last_address_vaddr = entry->vaddr_base; - - return last_address_vaddr + address_offset; -} - -void qemu_invalidate_map_cache(void) -{ - unsigned long i; - - mapcache_lock(); - - for (i = 0; i < nr_buckets; i++) { - struct map_cache *entry = &mapcache_entry[i]; - - if (entry->vaddr_base == NULL) - continue; - - errno = munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE); - if (errno) { - fprintf(logfile, "unmap fails %d\n", errno); - exit(-1); - } - - entry->paddr_index = 0; - entry->vaddr_base = NULL; - } - - last_address_index = ~0UL; - last_address_vaddr = NULL; - - mapcache_unlock(); -} - -#endif /* defined(MAPCACHE) */ int main(int argc, char **argv) { @@ -7040,14 +6893,6 @@ int main(int argc, char **argv) char usb_devices[MAX_USB_CMDLINE][128]; int usb_devices_index; int fds[2]; - unsigned long ioreq_pfn; - extern void *shared_page; - extern void *buffered_io_page; -#ifdef __ia64__ - unsigned long nr_pages; - xen_pfn_t *page_array; - extern void *buffered_pio_page; -#endif sigset_t set; char qemu_dm_logfilename[128]; @@ -7602,6 +7447,7 @@ int main(int argc, char **argv) #ifdef CONFIG_DM bdrv_init(); + xc_handle = xc_interface_open(); xenstore_parse_domain_config(domid); #endif /* CONFIG_DM */ @@ -7695,83 +7541,6 @@ int main(int argc, char **argv) } phys_ram_size += ret; } -#endif /* !CONFIG_DM */ - -#ifdef CONFIG_DM - - xc_handle = xc_interface_open(); - -#if defined(__i386__) || defined(__x86_64__) - - if (qemu_map_cache_init()) { - fprintf(logfile, "qemu_map_cache_init returned: error %d\n", errno); - exit(-1); - } - - xc_get_hvm_param(xc_handle, domid, HVM_PARAM_IOREQ_PFN, &ioreq_pfn); - fprintf(logfile, "shared page at pfn %lx\n", ioreq_pfn); - shared_page = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, - PROT_READ|PROT_WRITE, ioreq_pfn); - if (shared_page == NULL) { - fprintf(logfile, "map shared IO page returned error %d\n", errno); - exit(-1); - } - - xc_get_hvm_param(xc_handle, domid, HVM_PARAM_BUFIOREQ_PFN, &ioreq_pfn); - fprintf(logfile, "buffered io page at pfn %lx\n", ioreq_pfn); - buffered_io_page = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, - PROT_READ|PROT_WRITE, ioreq_pfn); - if (buffered_io_page == NULL) { - fprintf(logfile, "map buffered IO page returned error %d\n", errno); - exit(-1); - } - -#elif defined(__ia64__) - - nr_pages = ram_size/PAGE_SIZE; - - page_array = (xen_pfn_t *)malloc(nr_pages * sizeof(xen_pfn_t)); - if (page_array == NULL) { - fprintf(logfile, "malloc returned error %d\n", errno); - exit(-1); - } - - shared_page = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, - PROT_READ|PROT_WRITE, - IO_PAGE_START >> PAGE_SHIFT); - - buffered_io_page =xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, - PROT_READ|PROT_WRITE, - BUFFER_IO_PAGE_START >> PAGE_SHIFT); - - buffered_pio_page = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, - PROT_READ|PROT_WRITE, - BUFFER_PIO_PAGE_START >> PAGE_SHIFT); - - for (i = 0; i < nr_pages; i++) - page_array[i] = i; - - /* VTI will not use memory between 3G~4G, so we just pass a legal pfn - to make QEMU map continuous virtual memory space */ - if (ram_size > MMIO_START) { - for (i = 0 ; i < (MEM_G >> PAGE_SHIFT); i++) - page_array[(MMIO_START >> PAGE_SHIFT) + i] - (STORE_PAGE_START >> PAGE_SHIFT); - } - - phys_ram_base = xc_map_foreign_batch(xc_handle, domid, - PROT_READ|PROT_WRITE, - page_array, nr_pages); - if (phys_ram_base == 0) { - fprintf(logfile, "xc_map_foreign_batch returned error %d\n", errno); - exit(-1); - } - free(page_array); -#endif - - timeoffset_get(); - -#else /* !CONFIG_DM */ phys_ram_base = qemu_vmalloc(phys_ram_size); if (!phys_ram_base) { @@ -7779,9 +7548,6 @@ int main(int argc, char **argv) exit(1); } -#endif /* !CONFIG_DM */ - -#ifndef CONFIG_DM /* we always create the cdrom drive, even if no disk is there */ bdrv_init(); if (cdrom_index >= 0) { diff -r 7953164cebb6 tools/ioemu/vl.h --- a/tools/ioemu/vl.h Tue Aug 07 09:07:29 2007 +0100 +++ b/tools/ioemu/vl.h Wed Aug 15 14:14:55 2007 -0400 @@ -1118,6 +1118,9 @@ extern void pci_piix4_acpi_init(PCIBus * /* pc.c */ extern QEMUMachine pc_machine; extern QEMUMachine isapc_machine; +#ifdef CONFIG_DM +extern QEMUMachine xenfv_machine; +#endif extern int fd_bootchk; void ioport_set_a20(int enable); -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=| _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel P. Berrange
2007-Aug-15 20:04 UTC
Re: [Xen-devel] PATCH: 2/10: Add a QEMU machine type for paravirt guests
This patch adds a paravirt machine type to QEMU. THis can be requested by passing the arg ''-M xenpv'' to qemu-dm. Aside from -d, and -domain-name, the only other args that are processed are the VNC / SDL graphics related args. Any others will be ignored. A tweak to helper2.c was made to stop it setting up a file handler watch when there are no CPUs registered. The paravirt machine is in hw/xen_machine_pv.c and registers an instance of the xenfb class, integrating it with the QEMU event loop and key/mouse handlers. A couple of methods were adding to xenfb.h to allow direct access to the file handles for xenstore & the event channel. The vfbif.py device controller is modified to launch qemu-dm instead of the old xen-vncfb / sdlfb daemons. When receiving framebuffer updates from the guest, the update has to be copied into QEMU''s copy of the framebuffer. This is because QEMU stores the framebuffer in the format that is native to the SDL display, or VNC client. This is not neccessarily the same as the guest framebuffer which is always 32bpp. If there is an exact depth match we use memcpy for speed, but in the non-matching case we have to fallback to slow code to covert pixel formats. It fully supports all features of the paravirt framebuffer including the choice between absolute & relative pointers. To avoid both moving the xenfb.c and making changes to it in the same patch, this just uses a Makefile hack to link against the xenfb.o from the tools/xenfb/ directory. This will be removed in the following patch. b/tools/ioemu/hw/xen_machine_pv.c | 231 ++++++++++++++++++++++++++++++++++ tools/ioemu/Makefile.target | 2 tools/ioemu/target-i386-dm/helper2.c | 5 tools/ioemu/vl.c | 5 tools/ioemu/vl.h | 1 tools/python/xen/xend/server/vfbif.py | 26 +-- tools/xenfb/xenfb.c | 80 ++++++++--- tools/xenfb/xenfb.h | 4 8 files changed, 317 insertions(+), 37 deletions(-) Signed-off-by: Daniel P. Berrange <berrange@redhat.com> Dan. diff -r 327024163186 tools/ioemu/Makefile.target --- a/tools/ioemu/Makefile.target Tue Aug 14 12:52:54 2007 -0400 +++ b/tools/ioemu/Makefile.target Tue Aug 14 13:26:18 2007 -0400 @@ -401,6 +401,8 @@ VL_OBJS+= xenstore.o VL_OBJS+= xenstore.o VL_OBJS+= xen_platform.o VL_OBJS+= xen_machine_fv.o +VL_OBJS+= xen_machine_pv.o +VL_OBJS+= ../../xenfb/xenfb.o VL_OBJS+= tpm_tis.o CPPFLAGS += -DHAS_AUDIO endif diff -r 327024163186 tools/ioemu/hw/xen_machine_pv.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/ioemu/hw/xen_machine_pv.c Tue Aug 14 14:21:29 2007 -0400 @@ -0,0 +1,231 @@ +/* + * QEMU Xen PV Machine + * + * Copyright (c) 2007 Red Hat + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "vl.h" +#include "../../xenfb/xenfb.h" +#include <linux/input.h> + +/* A convenient function for munging pixels between different depths */ +#define BLT(SRC_T,DST_T,RLS,GLS,BLS,RRS,GRS,BRS,RM,GM,BM) \ + for (line = y ; line < h ; line++) { \ + SRC_T *src = (SRC_T *)(xenfb->pixels + (line*xenfb->row_stride) + (x*xenfb->depth/8)); \ + DST_T *dst = (DST_T *)(ds->data + (line*ds->linesize) + (x*ds->depth/8)); \ + int col; \ + for (col = x ; col < w ; col++) { \ + *dst = (((*src >> RRS)&RM) << RLS) | \ + (((*src >> GRS)&GM) << GLS) | \ + (((*src >> GRS)&BM) << BLS); \ + src++; \ + dst++; \ + } \ + } + + +/* This copies data from the guest framebuffer region, into QEMU''s copy + * NB. QEMU''s copy is stored in the pixel format of a) the local X server (SDL case) + * or b) the current VNC client pixel format. + */ +static void xen_pvfb_guest_copy(struct xenfb *xenfb, int x, int y, int w, int h) +{ + DisplayState *ds = (DisplayState *)xenfb->user_data; + int line; + + if (xenfb->depth == ds->depth) { /* Perfect match can use fast path */ + for (line = y ; line < (y+h) ; line++) { + memcpy(ds->data + (line * ds->linesize) + (x*ds->depth/8), + xenfb->pixels + (line*xenfb->row_stride) + (x*xenfb->depth/8), + w * xenfb->depth/8); + } + } else { /* Mismatch requires slow pixel munging */ + if (xenfb->depth == 8) { + /* 8 bit source == r:3 g:3 b:2 */ + if (ds->depth == 16) { + BLT(uint8_t, uint16_t, 5, 2, 0, 11, 5, 0, 7, 7, 3); + } else if (ds->depth == 32) { + BLT(uint8_t, uint32_t, 5, 2, 0, 16, 8, 0, 7, 7, 3); + } + } else if (xenfb->depth == 16) { + /* 16 bit source == r:5 g:6 b:5 */ + if (ds->depth == 8) { + BLT(uint16_t, uint8_t, 11, 5, 0, 5, 2, 0, 31, 63, 31); + } else if (ds->depth == 32) { + BLT(uint16_t, uint32_t, 11, 5, 0, 16, 8, 0, 31, 63, 31); + } + } else if (xenfb->depth == 32) { + /* 32 bit source == r:8 g:8 b:8 (padding:8) */ + if (ds->depth == 8) { + BLT(uint32_t, uint8_t, 16, 8, 0, 5, 2, 0, 255, 255, 255); + } else if (ds->depth == 16) { + BLT(uint32_t, uint16_t, 16, 8, 0, 11, 5, 0, 255, 255, 255); + } + } + } + dpy_update(ds, x, y, w, h); +} + + +/* Send a keypress from the client to the guest OS */ +static void xen_pvfb_put_keycode(void *opaque, int keycode) +{ + struct xenfb *xenfb = (struct xenfb*)opaque; + xenfb_send_key(xenfb, keycode & 0x80 ? 0 : 1, keycode & 0x7f); +} + +/* Send a mouse event from the client to the guest OS */ +static void xen_pvfb_mouse_event(void *opaque, + int dx, int dy, int dz, int button_state) +{ + static int old_state = 0; + int i; + struct xenfb *xenfb = (struct xenfb*)opaque; + DisplayState *ds = (DisplayState *)xenfb->user_data; + if (xenfb->abs_pointer_wanted) + xenfb_send_position(xenfb, + dx*ds->width/0x7fff, + dy*ds->height/0x7fff); + else + xenfb_send_motion(xenfb, dx, dy); + + for (i = 0 ; i < 8 ; i++) { + int lastDown = old_state & (1 << i); + int down = button_state & (1 << i); + if (down == lastDown) + continue; + + if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0) + return; + } + old_state = button_state; +} + +/* QEMU display state changed, so refresh the framebuffer copy */ +void xen_pvfb_update(void *opaque) +{ + struct xenfb *xenfb = (struct xenfb *)opaque; + xen_pvfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height); +} + +/* QEMU display state changed, so refresh the framebuffer copy */ +void xen_pvfb_invalidate(void *opaque) +{ + struct xenfb *xenfb = (struct xenfb *)opaque; + xen_pvfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height); +} + +/* Screen dump is not used in Xen, so no need to impl this ? */ +void xen_pvfb_screen_dump(void *opaque, const char *name) { } + +void xen_pvfb_dispatch_store(void *opaque) { + int ret; + if ((ret = xenfb_dispatch_store((struct xenfb *)opaque)) < 0) { + fprintf(stderr, "Failure while dispatching store: %d\n", ret); + exit(1); + } +} + +void xen_pvfb_dispatch_channel(void *opaque) { + int ret; + if ((ret = xenfb_dispatch_channel((struct xenfb *)opaque)) < 0) { + fprintf(stderr, "Failure while dispatching store: %d\n", ret); + exit(1); + } +} + +/* The Xen PV machine currently provides + * - a virtual framebuffer + * - .... + */ +static void xen_init_pv(uint64_t ram_size, int vga_ram_size, char *boot_device, + DisplayState *ds, const char **fd_filename, + int snapshot, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename) +{ + struct xenfb *xenfb; + extern int domid; + int fd; + + /* Prepare PVFB state */ + xenfb = xenfb_new(); + if (xenfb == NULL) { + fprintf(stderr, "Could not create framebuffer (%s)\n", + strerror(errno)); + exit(1); + } + + /* Talk to the guest */ + if (xenfb_attach_dom(xenfb, domid) < 0) { + fprintf(stderr, "Could not connect to domain (%s)\n", + strerror(errno)); + exit(1); + } + xenfb->update = xen_pvfb_guest_copy; + xenfb->user_data = ds; + + /* Tell QEMU to allocate a graphical console */ + graphic_console_init(ds, + xen_pvfb_update, + xen_pvfb_invalidate, + xen_pvfb_screen_dump, + xenfb); + + /* Register our keyboard & mouse handlers */ + qemu_add_kbd_event_handler(xen_pvfb_put_keycode, xenfb); + qemu_add_mouse_event_handler(xen_pvfb_mouse_event, xenfb, + xenfb->abs_pointer_wanted, + "Xen PVFB Mouse"); + + /* Listen for events from xenstore */ + fd = xenfb_get_store_fd(xenfb); + if (qemu_set_fd_handler2(fd, NULL, xen_pvfb_dispatch_store, NULL, xenfb) < 0) { + fprintf(stderr, "Could not register event handler (%s)\n", + strerror(errno)); + } + + /* Listen for events from the event channel */ + fd = xenfb_get_channel_fd(xenfb); + if (qemu_set_fd_handler2(fd, NULL, xen_pvfb_dispatch_channel, NULL, xenfb) < 0) { + fprintf(stderr, "Could not register event handler (%s)\n", + strerror(errno)); + } + + /* Setup QEMU display */ + dpy_resize(ds, xenfb->width, xenfb->height); +} + +QEMUMachine xenpv_machine = { + "xenpv", + "Xen Para-virtualized PC", + xen_init_pv, +}; + +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -r 327024163186 tools/ioemu/target-i386-dm/helper2.c --- a/tools/ioemu/target-i386-dm/helper2.c Tue Aug 14 12:52:54 2007 -0400 +++ b/tools/ioemu/target-i386-dm/helper2.c Tue Aug 14 12:58:46 2007 -0400 @@ -616,7 +616,7 @@ int main_loop(void) extern int shutdown_requested; extern int suspend_requested; CPUState *env = cpu_single_env; - int evtchn_fd = xc_evtchn_fd(xce_handle); + int evtchn_fd = xce_handle == -1 ? -1 : xc_evtchn_fd(xce_handle); char qemu_file[PATH_MAX]; fd_set fds; @@ -624,7 +624,8 @@ int main_loop(void) cpu_single_env); qemu_mod_timer(buffered_io_timer, qemu_get_clock(rt_clock)); - qemu_set_fd_handler(evtchn_fd, cpu_handle_ioreq, NULL, env); + if (evtchn_fd != -1) + qemu_set_fd_handler(evtchn_fd, cpu_handle_ioreq, NULL, env); xenstore_record_dm_state("running"); while (1) { diff -r 327024163186 tools/ioemu/vl.c --- a/tools/ioemu/vl.c Tue Aug 14 12:52:54 2007 -0400 +++ b/tools/ioemu/vl.c Tue Aug 14 13:50:44 2007 -0400 @@ -182,7 +182,7 @@ extern int vcpus; int xc_handle; -char domain_name[64] = "Xen-HVM-no-name"; +char domain_name[64] = "Xen-no-name"; extern int domid; char vncpasswd[64]; @@ -6651,6 +6651,7 @@ void register_machines(void) qemu_register_machine(&isapc_machine); #else qemu_register_machine(&xenfv_machine); + qemu_register_machine(&xenpv_machine); #endif #elif defined(TARGET_PPC) qemu_register_machine(&heathrow_machine); @@ -7370,7 +7371,7 @@ int main(int argc, char **argv) break; case QEMU_OPTION_domainname: snprintf(domain_name, sizeof(domain_name), - "Xen-HVM-%s", optarg); + "Xen-%s", optarg); break; case QEMU_OPTION_d: domid = atoi(optarg); diff -r 327024163186 tools/ioemu/vl.h --- a/tools/ioemu/vl.h Tue Aug 14 12:52:54 2007 -0400 +++ b/tools/ioemu/vl.h Tue Aug 14 12:55:35 2007 -0400 @@ -1120,6 +1120,7 @@ extern QEMUMachine isapc_machine; extern QEMUMachine isapc_machine; #ifdef CONFIG_DM extern QEMUMachine xenfv_machine; +extern QEMUMachine xenpv_machine; #endif extern int fd_bootchk; diff -r 327024163186 tools/python/xen/xend/server/vfbif.py --- a/tools/python/xen/xend/server/vfbif.py Tue Aug 14 12:52:54 2007 -0400 +++ b/tools/python/xen/xend/server/vfbif.py Tue Aug 14 14:15:52 2007 -0400 @@ -50,8 +50,10 @@ class VfbifController(DevController): # is HVM, so qemu-dm will handle the vfb. return - std_args = [ "--domid", "%d" % self.vm.getDomid(), - "--title", self.vm.getName() ] + args = [ xen.util.auxbin.pathTo("qemu-dm"), + "-M", "xenpv", + "-d", "%d" % self.vm.getDomid(), + "-domain-name", self.vm.getName() ] t = config.get("type", None) if t == "vnc": passwd = None @@ -65,15 +67,14 @@ class VfbifController(DevController): else: log.debug("No VNC passwd configured for vfb access") - # Try to start the vnc backend - args = [xen.util.auxbin.pathTo("xen-vncfb")] - if config.has_key("vncunused"): - args += ["--unused"] - elif config.has_key("vncdisplay"): - args += ["--vncport", "%d" % (5900 + int(config["vncdisplay"]))] - vnclisten = config.get("vnclisten", + vnclisten = config.get(''vnclisten'', xen.xend.XendOptions.instance().get_vnclisten_address()) - args += [ "--listen", vnclisten ] + vncdisplay = config.get(''vncdisplay'', 0) + args += [''-vnc'', "%s:%d" % (vnclisten, vncdisplay)] + + if config.get(''vncunused'', 0): + args += [''-vncunused''] + if config.has_key("keymap"): args += ["-k", "%s" % config["keymap"]] else: @@ -81,15 +82,14 @@ class VfbifController(DevController): if xoptions.get_keymap(): args += ["-k", "%s" % xoptions.get_keymap()] - spawn_detached(args[0], args + std_args, os.environ) + spawn_detached(args[0], args, os.environ) elif t == "sdl": - args = [xen.util.auxbin.pathTo("xen-sdlfb")] env = dict(os.environ) if config.has_key("display"): env[''DISPLAY''] = config["display"] if config.has_key("xauthority"): env[''XAUTHORITY''] = config["xauthority"] - spawn_detached(args[0], args + std_args, env) + spawn_detached(args[0], args, env) else: raise VmError(''Unknown vfb type %s (%s)'' % (t, repr(config))) diff -r 327024163186 tools/xenfb/xenfb.c --- a/tools/xenfb/xenfb.c Tue Aug 14 12:52:54 2007 -0400 +++ b/tools/xenfb/xenfb.c Tue Aug 14 13:41:54 2007 -0400 @@ -676,37 +676,58 @@ static int xenfb_on_state_change(struct return 0; } -/* Returns 0 normally, -1 on error, or -2 if the domain went away. */ -int xenfb_poll(struct xenfb *xenfb_pub, fd_set *readfds) +int xenfb_dispatch_channel(struct xenfb *xenfb_pub) { struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; evtchn_port_t port; + port = xc_evtchn_pending(xenfb->evt_xch); + if (port == -1) + return -1; + + if (port == xenfb->fb.port) + xenfb_on_fb_event(xenfb); + else if (port == xenfb->kbd.port) + xenfb_on_kbd_event(xenfb); + + if (xc_evtchn_unmask(xenfb->evt_xch, port) == -1) + return -1; + + return 0; +} + +int xenfb_dispatch_store(struct xenfb *xenfb_pub) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; unsigned dummy; char **vec; int r; + vec = xs_read_watch(xenfb->xsh, &dummy); + free(vec); + r = xenfb_on_state_change(&xenfb->fb); + if (r == 0) + r = xenfb_on_state_change(&xenfb->kbd); + if (r == -1) + return -2; + + return 0; +} + + +/* Returns 0 normally, -1 on error, or -2 if the domain went away. */ +int xenfb_poll(struct xenfb *xenfb_pub, fd_set *readfds) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + int ret; + if (FD_ISSET(xc_evtchn_fd(xenfb->evt_xch), readfds)) { - port = xc_evtchn_pending(xenfb->evt_xch); - if (port == -1) - return -1; - - if (port == xenfb->fb.port) - xenfb_on_fb_event(xenfb); - else if (port == xenfb->kbd.port) - xenfb_on_kbd_event(xenfb); - - if (xc_evtchn_unmask(xenfb->evt_xch, port) == -1) - return -1; + if ((ret = xenfb_dispatch_channel(xenfb_pub)) < 0) + return ret; } if (FD_ISSET(xs_fileno(xenfb->xsh), readfds)) { - vec = xs_read_watch(xenfb->xsh, &dummy); - free(vec); - r = xenfb_on_state_change(&xenfb->fb); - if (r == 0) - r = xenfb_on_state_change(&xenfb->kbd); - if (r == -1) - return -2; + if ((ret = xenfb_dispatch_store(xenfb_pub)) < 0) + return ret; } return 0; @@ -721,6 +742,18 @@ int xenfb_select_fds(struct xenfb *xenfb FD_SET(fd1, readfds); FD_SET(fd2, readfds); return fd1 > fd2 ? fd1 + 1 : fd2 + 1; +} + +int xenfb_get_store_fd(struct xenfb *xenfb_pub) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + return xs_fileno(xenfb->xsh); +} + +int xenfb_get_channel_fd(struct xenfb *xenfb_pub) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + return xc_evtchn_fd(xenfb->evt_xch); } static int xenfb_kbd_event(struct xenfb_private *xenfb, @@ -783,3 +816,10 @@ int xenfb_send_position(struct xenfb *xe return xenfb_kbd_event(xenfb, &event); } +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff -r 327024163186 tools/xenfb/xenfb.h --- a/tools/xenfb/xenfb.h Tue Aug 14 12:52:54 2007 -0400 +++ b/tools/xenfb/xenfb.h Tue Aug 14 13:42:04 2007 -0400 @@ -25,8 +25,12 @@ void xenfb_teardown(struct xenfb *xenfb) int xenfb_attach_dom(struct xenfb *xenfb, int domid); +int xenfb_dispatch_store(struct xenfb *xenfb_pub); +int xenfb_dispatch_channel(struct xenfb *xenfb_pub); int xenfb_select_fds(struct xenfb *xenfb, fd_set *readfds); int xenfb_poll(struct xenfb *xenfb, fd_set *readfds); +int xenfb_get_store_fd(struct xenfb *xenfb_pub); +int xenfb_get_channel_fd(struct xenfb *xenfb_pub); int xenfb_send_key(struct xenfb *xenfb, bool down, int keycode); int xenfb_send_motion(struct xenfb *xenfb, int rel_x, int rel_y); -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=| _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel P. Berrange
2007-Aug-15 20:05 UTC
Re: [Xen-devel] PATCH: 3/10: Remove standalone xenfb code
This patch removes all trace of the standalone paravirt framebuffer daemon. With this there is no longer any requirement for LibVNCServer. Everything is handled by the QEMU device model. The xenfb.c and xenfb.h files are now moved (without code change) into tools/ioemu/hw/ & the temporary Makefile hack from the previous patch is removed. Config.mk | 1 a/tools/check/check_libvncserver | 38 - a/tools/check/check_sdl | 27 - a/tools/xenfb/Makefile | 32 - a/tools/xenfb/sdlfb.c | 342 ---------------- a/tools/xenfb/vncfb.c | 522 ------------------------ a/tools/xenfb/xenfb.c | 825 --------------------------------------- a/tools/xenfb/xenfb.h | 39 - b/tools/ioemu/hw/xenfb.c | 825 +++++++++++++++++++++++++++++++++++++++ b/tools/ioemu/hw/xenfb.h | 39 + tools/Makefile | 1 tools/check/Makefile | 4 tools/ioemu/Makefile.target | 2 tools/ioemu/hw/xen_machine_pv.c | 2 14 files changed, 868 insertions(+), 1831 deletions(-) Signed-off-by: Daniel P. Berrange <berrange@redhat.com> Dan. diff -r 450e0143acaf Config.mk --- a/Config.mk Tue Aug 14 14:31:01 2007 -0400 +++ b/Config.mk Tue Aug 14 14:35:18 2007 -0400 @@ -85,7 +85,6 @@ XENSTAT_XENTOP ?= y XENSTAT_XENTOP ?= y VTPM_TOOLS ?= n LIBXENAPI_BINDINGS ?= n -XENFB_TOOLS ?= n PYTHON_TOOLS ?= y -include $(XEN_ROOT)/.config diff -r 450e0143acaf tools/Makefile --- a/tools/Makefile Tue Aug 14 14:31:01 2007 -0400 +++ b/tools/Makefile Tue Aug 14 14:34:30 2007 -0400 @@ -19,7 +19,6 @@ SUBDIRS-y += libaio SUBDIRS-y += libaio SUBDIRS-y += blktap SUBDIRS-y += libfsimage -SUBDIRS-$(XENFB_TOOLS) += xenfb SUBDIRS-$(LIBXENAPI_BINDINGS) += libxen # These don''t cross-compile diff -r 450e0143acaf tools/check/Makefile --- a/tools/check/Makefile Tue Aug 14 14:31:01 2007 -0400 +++ b/tools/check/Makefile Tue Aug 14 14:37:27 2007 -0400 @@ -7,7 +7,7 @@ all: build # Check this machine is OK for building on. .PHONY: build build: - XENFB_TOOLS=$(XENFB_TOOLS) LIBXENAPI_BINDINGS=$(LIBXENAPI_BINDINGS) ./chk build + LIBXENAPI_BINDINGS=$(LIBXENAPI_BINDINGS) ./chk build # Check this machine is OK for installing on. # DO NOT use this check from ''make install'' in the parent @@ -15,7 +15,7 @@ build: # copy rather than actually installing. .PHONY: install install: - XENFB_TOOLS=$(XENFB_TOOLS) LIBXENAPI_BINDINGS=$(LIBXENAPI_BINDINGS) ./chk install + LIBXENAPI_BINDINGS=$(LIBXENAPI_BINDINGS) ./chk install .PHONY: clean clean: diff -r 450e0143acaf tools/check/check_libvncserver --- a/tools/check/check_libvncserver Tue Aug 14 14:31:01 2007 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -#!/bin/sh -# CHECK-BUILD CHECK-INSTALL - -if [ ! "$XENFB_TOOLS" = "y" ] -then - echo -n "unused, " - exit 0 -fi - -RC=0 - -LIBVNCSERVER_CONFIG="$(which libvncserver-config)" -tmpfile=$(mktemp) - -if test -z ${LIBVNCSERVER_CONFIG}; then - RC=1 -else - ${LIBVNCSERVER_CONFIG} --libs 2>&1 > /dev/null - RC=$? -fi - -if test $RC -ne 0; then - echo "FAILED" - echo " *** libvncserver-config is missing. " - echo " *** Please install libvncserver." -elif ! ld $($LIBVNCSERVER_CONFIG --libs) -o $tmpfile >/dev/null 2>&1; then - echo "FAILED" - echo " *** dependency libraries for libvncserver are missing: " - RC=1 - for i in $(ld $($LIBVNCSERVER_CONFIG --libs) -o $tmpfile 2>&1 >/dev/null); do - case $i in - -l*) echo lib${i#-l} - esac - done -fi -rm -f $tmpfile - -exit $RC diff -r 450e0143acaf tools/check/check_sdl --- a/tools/check/check_sdl Tue Aug 14 14:31:01 2007 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -#!/bin/sh -# CHECK-BUILD CHECK-INSTALL - -if [ ! "$XENFB_TOOLS" = "y" ] -then - echo -n "unused, " - exit 0 -fi - -RC=0 - -SDL_CONFIG="$(which sdl-config)" - -if test -z ${SDL_CONFIG}; then - RC=1 -else - ${SDL_CONFIG} --libs 2>&1 > /dev/null - RC=$? -fi - -if test $RC -ne 0; then - echo "FAILED" - echo " *** sdl-config is missing. " - echo " *** Please install libsdl-dev or sdl." -fi - -exit $RC diff -r 450e0143acaf tools/ioemu/Makefile.target --- a/tools/ioemu/Makefile.target Tue Aug 14 14:31:01 2007 -0400 +++ b/tools/ioemu/Makefile.target Tue Aug 14 14:35:38 2007 -0400 @@ -402,7 +402,7 @@ VL_OBJS+= xen_platform.o VL_OBJS+= xen_platform.o VL_OBJS+= xen_machine_fv.o VL_OBJS+= xen_machine_pv.o -VL_OBJS+= ../../xenfb/xenfb.o +VL_OBJS+= xenfb.o VL_OBJS+= tpm_tis.o CPPFLAGS += -DHAS_AUDIO endif diff -r 450e0143acaf tools/ioemu/hw/xen_machine_pv.c --- a/tools/ioemu/hw/xen_machine_pv.c Tue Aug 14 14:31:01 2007 -0400 +++ b/tools/ioemu/hw/xen_machine_pv.c Tue Aug 14 14:35:58 2007 -0400 @@ -23,7 +23,7 @@ */ #include "vl.h" -#include "../../xenfb/xenfb.h" +#include "xenfb.h" #include <linux/input.h> /* A convenient function for munging pixels between different depths */ diff -r 450e0143acaf tools/ioemu/hw/xenfb.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/ioemu/hw/xenfb.c Tue Aug 14 14:33:37 2007 -0400 @@ -0,0 +1,825 @@ +#include <stdarg.h> +#include <stdlib.h> +#include <sys/types.h> +#include <fcntl.h> +#include <unistd.h> +#include <xenctrl.h> +#include <xen/io/xenbus.h> +#include <xen/io/fbif.h> +#include <xen/io/kbdif.h> +#include <xen/io/protocols.h> +#include <sys/select.h> +#include <stdbool.h> +#include <xen/event_channel.h> +#include <sys/mman.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <xs.h> + +#include "xenfb.h" + +// FIXME defend against malicious frontend? + +struct xenfb_device { + const char *devicetype; + char nodename[64]; /* backend xenstore dir */ + char otherend[64]; /* frontend xenstore dir */ + int otherend_id; /* frontend domid */ + enum xenbus_state state; /* backend state */ + void *page; /* shared page */ + evtchn_port_t port; + struct xenfb_private *xenfb; +}; + +struct xenfb_private { + struct xenfb pub; + int evt_xch; /* event channel driver handle */ + int xc; /* hypervisor interface handle */ + struct xs_handle *xsh; /* xs daemon handle */ + struct xenfb_device fb, kbd; + size_t fb_len; /* size of framebuffer */ + char protocol[64]; /* frontend protocol */ +}; + +static void xenfb_detach_dom(struct xenfb_private *); + +static char *xenfb_path_in_dom(struct xs_handle *xsh, + char *buf, size_t size, + unsigned domid, const char *fmt, ...) +{ + va_list ap; + char *domp = xs_get_domain_path(xsh, domid); + int n; + + if (domp == NULL) + return NULL; + + n = snprintf(buf, size, "%s/", domp); + free(domp); + if (n >= size) + return NULL; + + va_start(ap, fmt); + n += vsnprintf(buf + n, size - n, fmt, ap); + va_end(ap); + if (n >= size) + return NULL; + + return buf; +} + +static int xenfb_xs_scanf1(struct xs_handle *xsh, + const char *dir, const char *node, + const char *fmt, void *dest) +{ + char buf[1024]; + char *p; + int ret; + + if (snprintf(buf, sizeof(buf), "%s/%s", dir, node) >= sizeof(buf)) { + errno = ENOENT; + return -1; + } + p = xs_read(xsh, XBT_NULL, buf, NULL); + if (!p) { + errno = ENOENT; + return -1; + } + ret = sscanf(p, fmt, dest); + free(p); + if (ret != 1) { + errno = EDOM; + return -1; + } + return ret; +} + +static int xenfb_xs_printf(struct xs_handle *xsh, + const char *dir, const char *node, char *fmt, ...) +{ + va_list ap; + char key[1024]; + char val[1024]; + int n; + + if (snprintf(key, sizeof(key), "%s/%s", dir, node) >= sizeof(key)) { + errno = ENOENT; + return -1; + } + + va_start(ap, fmt); + n = vsnprintf(val, sizeof(val), fmt, ap); + va_end(ap); + if (n >= sizeof(val)) { + errno = ENOSPC; /* close enough */ + return -1; + } + + if (!xs_write(xsh, XBT_NULL, key, val, n)) + return -1; + return 0; +} + +static void xenfb_device_init(struct xenfb_device *dev, + const char *type, + struct xenfb_private *xenfb) +{ + dev->devicetype = type; + dev->otherend_id = -1; + dev->port = -1; + dev->xenfb = xenfb; +} + +int xenfb_device_set_domain(struct xenfb_device *dev, int domid) +{ + struct xenfb_private *xenfb = dev->xenfb; + + dev->otherend_id = domid; + + if (!xenfb_path_in_dom(xenfb->xsh, + dev->otherend, sizeof(dev->otherend), + domid, "device/%s/0", dev->devicetype)) { + errno = ENOENT; + return -1; + } + if (!xenfb_path_in_dom(xenfb->xsh, + dev->nodename, sizeof(dev->nodename), + 0, "backend/%s/%d/0", dev->devicetype, domid)) { + errno = ENOENT; + return -1; + } + + return 0; +} + +struct xenfb *xenfb_new(void) +{ + struct xenfb_private *xenfb = malloc(sizeof(*xenfb)); + int serrno; + + if (xenfb == NULL) + return NULL; + + memset(xenfb, 0, sizeof(*xenfb)); + xenfb->evt_xch = xenfb->xc = -1; + xenfb_device_init(&xenfb->fb, "vfb", xenfb); + xenfb_device_init(&xenfb->kbd, "vkbd", xenfb); + + xenfb->evt_xch = xc_evtchn_open(); + if (xenfb->evt_xch == -1) + goto fail; + + xenfb->xc = xc_interface_open(); + if (xenfb->xc == -1) + goto fail; + + xenfb->xsh = xs_daemon_open(); + if (!xenfb->xsh) + goto fail; + + return &xenfb->pub; + + fail: + serrno = errno; + xenfb_delete(&xenfb->pub); + errno = serrno; + return NULL; +} + +/* Remove the backend area in xenbus since the framebuffer really is + going away. */ +void xenfb_teardown(struct xenfb *xenfb_pub) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + + xs_rm(xenfb->xsh, XBT_NULL, xenfb->fb.nodename); + xs_rm(xenfb->xsh, XBT_NULL, xenfb->kbd.nodename); +} + + +void xenfb_delete(struct xenfb *xenfb_pub) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + + xenfb_detach_dom(xenfb); + if (xenfb->xc >= 0) + xc_interface_close(xenfb->xc); + if (xenfb->evt_xch >= 0) + xc_evtchn_close(xenfb->evt_xch); + if (xenfb->xsh) + xs_daemon_close(xenfb->xsh); + free(xenfb); +} + +static enum xenbus_state xenfb_read_state(struct xs_handle *xsh, + const char *dir) +{ + int ret, state; + + ret = xenfb_xs_scanf1(xsh, dir, "state", "%d", &state); + if (ret < 0) + return XenbusStateUnknown; + + if ((unsigned)state > XenbusStateClosed) + state = XenbusStateUnknown; + return state; +} + +static int xenfb_switch_state(struct xenfb_device *dev, + enum xenbus_state state) +{ + struct xs_handle *xsh = dev->xenfb->xsh; + + if (xenfb_xs_printf(xsh, dev->nodename, "state", "%d", state) < 0) + return -1; + dev->state = state; + return 0; +} + +static int xenfb_wait_for_state(struct xs_handle *xsh, const char *dir, + unsigned awaited) +{ + unsigned state, dummy; + char **vec; + + awaited |= 1 << XenbusStateUnknown; + + for (;;) { + state = xenfb_read_state(xsh, dir); + if ((1 << state) & awaited) + return state; + + vec = xs_read_watch(xsh, &dummy); + if (!vec) + return -1; + free(vec); + } +} + +static int xenfb_wait_for_backend_creation(struct xenfb_device *dev) +{ + struct xs_handle *xsh = dev->xenfb->xsh; + int state; + + if (!xs_watch(xsh, dev->nodename, "")) + return -1; + state = xenfb_wait_for_state(xsh, dev->nodename, + (1 << XenbusStateInitialising) + | (1 << XenbusStateClosed) +#if 1 /* TODO fudging state to permit restarting; to be removed */ + | (1 << XenbusStateInitWait) + | (1 << XenbusStateConnected) + | (1 << XenbusStateClosing) +#endif + ); + xs_unwatch(xsh, dev->nodename, ""); + + switch (state) { +#if 1 + case XenbusStateInitWait: + case XenbusStateConnected: + printf("Fudging state to %d\n", XenbusStateInitialising); /* FIXME */ +#endif + case XenbusStateInitialising: + case XenbusStateClosing: + case XenbusStateClosed: + break; + default: + return -1; + } + + return 0; +} + +static int xenfb_hotplug(struct xenfb_device *dev) +{ + if (xenfb_xs_printf(dev->xenfb->xsh, dev->nodename, + "hotplug-status", "connected")) + return -1; + return 0; +} + +static int xenfb_wait_for_frontend_initialised(struct xenfb_device *dev) +{ + switch (xenfb_wait_for_state(dev->xenfb->xsh, dev->otherend, +#if 1 /* TODO fudging state to permit restarting; to be removed */ + (1 << XenbusStateInitialised) + | (1 << XenbusStateConnected) +#else + 1 << XenbusStateInitialised, +#endif + )) { +#if 1 + case XenbusStateConnected: + printf("Fudging state to %d\n", XenbusStateInitialised); /* FIXME */ +#endif + case XenbusStateInitialised: + break; + default: + return -1; + } + + return 0; +} + +static void xenfb_copy_mfns(int mode, int count, unsigned long *dst, void *src) +{ + uint32_t *src32 = src; + uint64_t *src64 = src; + int i; + + for (i = 0; i < count; i++) + dst[i] = (mode == 32) ? src32[i] : src64[i]; +} + +static int xenfb_map_fb(struct xenfb_private *xenfb, int domid) +{ + struct xenfb_page *page = xenfb->fb.page; + int n_fbmfns; + int n_fbdirs; + unsigned long *pgmfns = NULL; + unsigned long *fbmfns = NULL; + void *map, *pd; + int mode, ret = -1; + + /* default to native */ + pd = page->pd; + mode = sizeof(unsigned long) * 8; + + if (0 == strlen(xenfb->protocol)) { + /* + * Undefined protocol, some guesswork needed. + * + * Old frontends which don''t set the protocol use + * one page directory only, thus pd[1] must be zero. + * pd[1] of the 32bit struct layout and the lower + * 32 bits of pd[0] of the 64bit struct layout have + * the same location, so we can check that ... + */ + uint32_t *ptr32 = NULL; + uint32_t *ptr64 = NULL; +#if defined(__i386__) + ptr32 = (void*)page->pd; + ptr64 = ((void*)page->pd) + 4; +#elif defined(__x86_64__) + ptr32 = ((void*)page->pd) - 4; + ptr64 = (void*)page->pd; +#endif + if (ptr32) { + if (0 == ptr32[1]) { + mode = 32; + pd = ptr32; + } else { + mode = 64; + pd = ptr64; + } + } +#if defined(__x86_64__) + } else if (0 == strcmp(xenfb->protocol, XEN_IO_PROTO_ABI_X86_32)) { + /* 64bit dom0, 32bit domU */ + mode = 32; + pd = ((void*)page->pd) - 4; +#elif defined(__i386__) + } else if (0 == strcmp(xenfb->protocol, XEN_IO_PROTO_ABI_X86_64)) { + /* 32bit dom0, 64bit domU */ + mode = 64; + pd = ((void*)page->pd) + 4; +#endif + } + + n_fbmfns = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE; + n_fbdirs = n_fbmfns * mode / 8; + n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE; + + pgmfns = malloc(sizeof(unsigned long) * n_fbdirs); + fbmfns = malloc(sizeof(unsigned long) * n_fbmfns); + if (!pgmfns || !fbmfns) + goto out; + + /* + * Bug alert: xc_map_foreign_batch() can fail partly and + * return a non-null value. This is a design flaw. When it + * happens, we happily continue here, and later crash on + * access. + */ + xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd); + map = xc_map_foreign_batch(xenfb->xc, domid, + PROT_READ, pgmfns, n_fbdirs); + if (map == NULL) + goto out; + xenfb_copy_mfns(mode, n_fbmfns, fbmfns, map); + munmap(map, n_fbdirs * XC_PAGE_SIZE); + + xenfb->pub.pixels = xc_map_foreign_batch(xenfb->xc, domid, + PROT_READ | PROT_WRITE, fbmfns, n_fbmfns); + if (xenfb->pub.pixels == NULL) + goto out; + + ret = 0; /* all is fine */ + + out: + if (pgmfns) + free(pgmfns); + if (fbmfns) + free(fbmfns); + return ret; +} + +static int xenfb_bind(struct xenfb_device *dev) +{ + struct xenfb_private *xenfb = dev->xenfb; + unsigned long mfn; + evtchn_port_t evtchn; + + if (xenfb_xs_scanf1(xenfb->xsh, dev->otherend, "page-ref", "%lu", + &mfn) < 0) + return -1; + if (xenfb_xs_scanf1(xenfb->xsh, dev->otherend, "event-channel", "%u", + &evtchn) < 0) + return -1; + + dev->port = xc_evtchn_bind_interdomain(xenfb->evt_xch, + dev->otherend_id, evtchn); + if (dev->port == -1) + return -1; + + dev->page = xc_map_foreign_range(xenfb->xc, dev->otherend_id, + XC_PAGE_SIZE, PROT_READ | PROT_WRITE, mfn); + if (dev->page == NULL) + return -1; + + return 0; +} + +static void xenfb_unbind(struct xenfb_device *dev) +{ + if (dev->page) { + munmap(dev->page, XC_PAGE_SIZE); + dev->page = NULL; + } + if (dev->port >= 0) { + xc_evtchn_unbind(dev->xenfb->evt_xch, dev->port); + dev->port = -1; + } +} + +static int xenfb_wait_for_frontend_connected(struct xenfb_device *dev) +{ + switch (xenfb_wait_for_state(dev->xenfb->xsh, dev->otherend, + 1 << XenbusStateConnected)) { + case XenbusStateConnected: + break; + default: + return -1; + } + + return 0; +} + +static void xenfb_dev_fatal(struct xenfb_device *dev, int err, + const char *fmt, ...) +{ + struct xs_handle *xsh = dev->xenfb->xsh; + va_list ap; + char errdir[80]; + char buf[1024]; + int n; + + fprintf(stderr, "%s ", dev->nodename); /* somewhat crude */ + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + if (err) + fprintf(stderr, " (%s)", strerror(err)); + putc(''\n'', stderr); + + if (!xenfb_path_in_dom(xsh, errdir, sizeof(errdir), 0, + "error/%s", dev->nodename)) + goto out; /* FIXME complain */ + + va_start(ap, fmt); + n = snprintf(buf, sizeof(buf), "%d ", err); + snprintf(buf + n, sizeof(buf) - n, fmt, ap); + va_end(ap); + + if (xenfb_xs_printf(xsh, buf, "error", "%s", buf) < 0) + goto out; /* FIXME complain */ + + out: + xenfb_switch_state(dev, XenbusStateClosing); +} + +int xenfb_attach_dom(struct xenfb *xenfb_pub, int domid) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + struct xs_handle *xsh = xenfb->xsh; + int val, serrno; + struct xenfb_page *fb_page; + + xenfb_detach_dom(xenfb); + + xenfb_device_set_domain(&xenfb->fb, domid); + xenfb_device_set_domain(&xenfb->kbd, domid); + + if (xenfb_wait_for_backend_creation(&xenfb->fb) < 0) + goto error; + if (xenfb_wait_for_backend_creation(&xenfb->kbd) < 0) + goto error; + + if (xenfb_xs_printf(xsh, xenfb->kbd.nodename, "feature-abs-pointer", "1")) + goto error; + if (xenfb_switch_state(&xenfb->fb, XenbusStateInitWait)) + goto error; + if (xenfb_switch_state(&xenfb->kbd, XenbusStateInitWait)) + goto error; + + if (xenfb_hotplug(&xenfb->fb) < 0) + goto error; + if (xenfb_hotplug(&xenfb->kbd) < 0) + goto error; + + if (!xs_watch(xsh, xenfb->fb.otherend, "")) + goto error; + if (!xs_watch(xsh, xenfb->kbd.otherend, "")) + goto error; + + if (xenfb_wait_for_frontend_initialised(&xenfb->fb) < 0) + goto error; + if (xenfb_wait_for_frontend_initialised(&xenfb->kbd) < 0) + goto error; + + if (xenfb_bind(&xenfb->fb) < 0) + goto error; + if (xenfb_bind(&xenfb->kbd) < 0) + goto error; + + if (xenfb_xs_scanf1(xsh, xenfb->fb.otherend, "feature-update", + "%d", &val) < 0) + val = 0; + if (!val) { + errno = ENOTSUP; + goto error; + } + if (xenfb_xs_scanf1(xsh, xenfb->fb.otherend, "protocol", "%63s", + xenfb->protocol) < 0) + xenfb->protocol[0] = ''\0''; + xenfb_xs_printf(xsh, xenfb->fb.nodename, "request-update", "1"); + + /* TODO check for permitted ranges */ + fb_page = xenfb->fb.page; + xenfb->pub.depth = fb_page->depth; + xenfb->pub.width = fb_page->width; + xenfb->pub.height = fb_page->height; + /* TODO check for consistency with the above */ + xenfb->fb_len = fb_page->mem_length; + xenfb->pub.row_stride = fb_page->line_length; + + if (xenfb_map_fb(xenfb, domid) < 0) + goto error; + + if (xenfb_switch_state(&xenfb->fb, XenbusStateConnected)) + goto error; + if (xenfb_switch_state(&xenfb->kbd, XenbusStateConnected)) + goto error; + + if (xenfb_wait_for_frontend_connected(&xenfb->kbd) < 0) + goto error; + if (xenfb_xs_scanf1(xsh, xenfb->kbd.otherend, "request-abs-pointer", + "%d", &val) < 0) + val = 0; + xenfb->pub.abs_pointer_wanted = val; + + return 0; + + error: + serrno = errno; + xenfb_detach_dom(xenfb); + xenfb_dev_fatal(&xenfb->fb, serrno, "on fire"); + xenfb_dev_fatal(&xenfb->kbd, serrno, "on fire"); + errno = serrno; + return -1; +} + +static void xenfb_detach_dom(struct xenfb_private *xenfb) +{ + xenfb_unbind(&xenfb->fb); + xenfb_unbind(&xenfb->kbd); + if (xenfb->pub.pixels) { + munmap(xenfb->pub.pixels, xenfb->fb_len); + xenfb->pub.pixels = NULL; + } +} + +static void xenfb_on_fb_event(struct xenfb_private *xenfb) +{ + uint32_t prod, cons; + struct xenfb_page *page = xenfb->fb.page; + + prod = page->out_prod; + if (prod == page->out_cons) + return; + rmb(); /* ensure we see ring contents up to prod */ + for (cons = page->out_cons; cons != prod; cons++) { + union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons); + + switch (event->type) { + case XENFB_TYPE_UPDATE: + if (xenfb->pub.update) + xenfb->pub.update(&xenfb->pub, + event->update.x, event->update.y, + event->update.width, event->update.height); + break; + } + } + mb(); /* ensure we''re done with ring contents */ + page->out_cons = cons; + xc_evtchn_notify(xenfb->evt_xch, xenfb->fb.port); +} + +static void xenfb_on_kbd_event(struct xenfb_private *xenfb) +{ + struct xenkbd_page *page = xenfb->kbd.page; + + /* We don''t understand any keyboard events, so just ignore them. */ + if (page->out_prod == page->out_cons) + return; + page->out_cons = page->out_prod; + xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port); +} + +static int xenfb_on_state_change(struct xenfb_device *dev) +{ + enum xenbus_state state; + + state = xenfb_read_state(dev->xenfb->xsh, dev->otherend); + + switch (state) { + case XenbusStateUnknown: + /* There was an error reading the frontend state. The + domain has probably gone away; in any case, there''s + not much point in us continuing. */ + return -1; + case XenbusStateInitialising: + case XenbusStateInitWait: + case XenbusStateInitialised: + case XenbusStateConnected: + break; + case XenbusStateClosing: + xenfb_unbind(dev); + xenfb_switch_state(dev, state); + break; + case XenbusStateClosed: + xenfb_switch_state(dev, state); + } + return 0; +} + +int xenfb_dispatch_channel(struct xenfb *xenfb_pub) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + evtchn_port_t port; + port = xc_evtchn_pending(xenfb->evt_xch); + if (port == -1) + return -1; + + if (port == xenfb->fb.port) + xenfb_on_fb_event(xenfb); + else if (port == xenfb->kbd.port) + xenfb_on_kbd_event(xenfb); + + if (xc_evtchn_unmask(xenfb->evt_xch, port) == -1) + return -1; + + return 0; +} + +int xenfb_dispatch_store(struct xenfb *xenfb_pub) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + unsigned dummy; + char **vec; + int r; + + vec = xs_read_watch(xenfb->xsh, &dummy); + free(vec); + r = xenfb_on_state_change(&xenfb->fb); + if (r == 0) + r = xenfb_on_state_change(&xenfb->kbd); + if (r == -1) + return -2; + + return 0; +} + + +/* Returns 0 normally, -1 on error, or -2 if the domain went away. */ +int xenfb_poll(struct xenfb *xenfb_pub, fd_set *readfds) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + int ret; + + if (FD_ISSET(xc_evtchn_fd(xenfb->evt_xch), readfds)) { + if ((ret = xenfb_dispatch_channel(xenfb_pub)) < 0) + return ret; + } + + if (FD_ISSET(xs_fileno(xenfb->xsh), readfds)) { + if ((ret = xenfb_dispatch_store(xenfb_pub)) < 0) + return ret; + } + + return 0; +} + +int xenfb_select_fds(struct xenfb *xenfb_pub, fd_set *readfds) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + int fd1 = xc_evtchn_fd(xenfb->evt_xch); + int fd2 = xs_fileno(xenfb->xsh); + + FD_SET(fd1, readfds); + FD_SET(fd2, readfds); + return fd1 > fd2 ? fd1 + 1 : fd2 + 1; +} + +int xenfb_get_store_fd(struct xenfb *xenfb_pub) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + return xs_fileno(xenfb->xsh); +} + +int xenfb_get_channel_fd(struct xenfb *xenfb_pub) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + return xc_evtchn_fd(xenfb->evt_xch); +} + +static int xenfb_kbd_event(struct xenfb_private *xenfb, + union xenkbd_in_event *event) +{ + uint32_t prod; + struct xenkbd_page *page = xenfb->kbd.page; + + if (xenfb->kbd.state != XenbusStateConnected) + return 0; + + prod = page->in_prod; + if (prod - page->in_cons == XENKBD_IN_RING_LEN) { + errno = EAGAIN; + return -1; + } + + mb(); /* ensure ring space available */ + XENKBD_IN_RING_REF(page, prod) = *event; + wmb(); /* ensure ring contents visible */ + page->in_prod = prod + 1; + return xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port); +} + +int xenfb_send_key(struct xenfb *xenfb_pub, bool down, int keycode) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + union xenkbd_in_event event; + + memset(&event, 0, XENKBD_IN_EVENT_SIZE); + event.type = XENKBD_TYPE_KEY; + event.key.pressed = down ? 1 : 0; + event.key.keycode = keycode; + + return xenfb_kbd_event(xenfb, &event); +} + +int xenfb_send_motion(struct xenfb *xenfb_pub, int rel_x, int rel_y) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + union xenkbd_in_event event; + + memset(&event, 0, XENKBD_IN_EVENT_SIZE); + event.type = XENKBD_TYPE_MOTION; + event.motion.rel_x = rel_x; + event.motion.rel_y = rel_y; + + return xenfb_kbd_event(xenfb, &event); +} + +int xenfb_send_position(struct xenfb *xenfb_pub, int abs_x, int abs_y) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + union xenkbd_in_event event; + + memset(&event, 0, XENKBD_IN_EVENT_SIZE); + event.type = XENKBD_TYPE_POS; + event.pos.abs_x = abs_x; + event.pos.abs_y = abs_y; + + return xenfb_kbd_event(xenfb, &event); +} +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff -r 450e0143acaf tools/ioemu/hw/xenfb.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/ioemu/hw/xenfb.h Tue Aug 14 14:33:40 2007 -0400 @@ -0,0 +1,39 @@ +#ifndef _XENFB_H_ +#define _XENFB_H_ + +#include <stdbool.h> +#include <sys/types.h> + +struct xenfb +{ + void *pixels; + + int row_stride; + int depth; + int width; + int height; + int abs_pointer_wanted; + + void *user_data; + + void (*update)(struct xenfb *xenfb, int x, int y, int width, int height); +}; + +struct xenfb *xenfb_new(void); +void xenfb_delete(struct xenfb *xenfb); +void xenfb_teardown(struct xenfb *xenfb); + +int xenfb_attach_dom(struct xenfb *xenfb, int domid); + +int xenfb_dispatch_store(struct xenfb *xenfb_pub); +int xenfb_dispatch_channel(struct xenfb *xenfb_pub); +int xenfb_select_fds(struct xenfb *xenfb, fd_set *readfds); +int xenfb_poll(struct xenfb *xenfb, fd_set *readfds); +int xenfb_get_store_fd(struct xenfb *xenfb_pub); +int xenfb_get_channel_fd(struct xenfb *xenfb_pub); + +int xenfb_send_key(struct xenfb *xenfb, bool down, int keycode); +int xenfb_send_motion(struct xenfb *xenfb, int rel_x, int rel_y); +int xenfb_send_position(struct xenfb *xenfb, int abs_x, int abs_y); + +#endif diff -r 450e0143acaf tools/xenfb/Makefile --- a/tools/xenfb/Makefile Tue Aug 14 14:31:01 2007 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -XEN_ROOT=../.. -include $(XEN_ROOT)/tools/Rules.mk - -CFLAGS += -I$(XEN_LIBXC) -I$(XEN_XENSTORE) -CFLAGS += -I$(XEN_ROOT)/tools/ioemu -LDFLAGS += -L$(XEN_LIBXC) -L$(XEN_XENSTORE) - -.PHONY: all -all: build - -.PHONY: build -build: - $(MAKE) vncfb sdlfb - -install: all - $(INSTALL_DIR) $(DESTDIR)/usr/$(LIBDIR)/xen/bin - $(INSTALL_PROG) vncfb $(DESTDIR)/usr/$(LIBDIR)/xen/bin/xen-vncfb - $(INSTALL_PROG) sdlfb $(DESTDIR)/usr/$(LIBDIR)/xen/bin/xen-sdlfb - -sdlfb: sdlfb.o xenfb.o - -sdlfb.o: CFLAGS += $(shell sdl-config --cflags) -sdlfb: LDLIBS += $(shell sdl-config --libs) -lxenctrl -lxenstore - -clean: - $(RM) *.o *~ vncfb sdlfb - -vncfb: vncfb.o xenfb.o -vncfb.o: CFLAGS += $(shell libvncserver-config --cflags) -vncfb: LDLIBS += $(shell libvncserver-config --libs) -lxenctrl -lxenstore - -sdlfb.o xenfb.o vncfb.o: xenfb.h diff -r 450e0143acaf tools/xenfb/sdlfb.c --- a/tools/xenfb/sdlfb.c Tue Aug 14 14:31:01 2007 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,342 +0,0 @@ -#include <SDL.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/select.h> -#include <stdlib.h> -#include <linux/input.h> -#include <getopt.h> -#include <string.h> -#include "xenfb.h" - -struct SDLFBData -{ - SDL_Surface *dst; - SDL_Surface *src; -}; - -/* - * Map from scancode to Linux input layer keycode. Scancodes are - * hardware-specific. This map assumes a standard AT or PS/2 - * keyboard. - * - * Why use scancodes? We can''t use key symbols, because they don''t - * identify keys --- they''re what keys are mapped to. The standard - * German keymap, for instance, maps both KEY_COMMA and KEY_102ND to - * SDLK_LESS. - */ -static int keymap[256] = { - [9] = KEY_ESC, - [10] = KEY_1, - [11] = KEY_2, - [12] = KEY_3, - [13] = KEY_4, - [14] = KEY_5, - [15] = KEY_6, - [16] = KEY_7, - [17] = KEY_8, - [18] = KEY_9, - [19] = KEY_0, - [20] = KEY_MINUS, - [21] = KEY_EQUAL, - [22] = KEY_BACKSPACE, - [23] = KEY_TAB, - [24] = KEY_Q, - [25] = KEY_W, - [26] = KEY_E, - [27] = KEY_R, - [28] = KEY_T, - [29] = KEY_Y, - [30] = KEY_U, - [31] = KEY_I, - [32] = KEY_O, - [33] = KEY_P, - [34] = KEY_LEFTBRACE, - [35] = KEY_RIGHTBRACE, - [36] = KEY_ENTER, - [37] = KEY_LEFTCTRL, - [38] = KEY_A, - [39] = KEY_S, - [40] = KEY_D, - [41] = KEY_F, - [42] = KEY_G, - [43] = KEY_H, - [44] = KEY_J, - [45] = KEY_K, - [46] = KEY_L, - [47] = KEY_SEMICOLON, - [48] = KEY_APOSTROPHE, - [49] = KEY_GRAVE, - [50] = KEY_LEFTSHIFT, - [51] = KEY_BACKSLASH, - [52] = KEY_Z, - [53] = KEY_X, - [54] = KEY_C, - [55] = KEY_V, - [56] = KEY_B, - [57] = KEY_N, - [58] = KEY_M, - [59] = KEY_COMMA, - [60] = KEY_DOT, - [61] = KEY_SLASH, - [62] = KEY_RIGHTSHIFT, - [63] = KEY_KPASTERISK, - [64] = KEY_LEFTALT, - [65] = KEY_SPACE, - [66] = KEY_CAPSLOCK, - [67] = KEY_F1, - [68] = KEY_F2, - [69] = KEY_F3, - [70] = KEY_F4, - [71] = KEY_F5, - [72] = KEY_F6, - [73] = KEY_F7, - [74] = KEY_F8, - [75] = KEY_F9, - [76] = KEY_F10, - [77] = KEY_NUMLOCK, - [78] = KEY_SCROLLLOCK, - [79] = KEY_KP7, - [80] = KEY_KP8, - [81] = KEY_KP9, - [82] = KEY_KPMINUS, - [83] = KEY_KP4, - [84] = KEY_KP5, - [85] = KEY_KP6, - [86] = KEY_KPPLUS, - [87] = KEY_KP1, - [88] = KEY_KP2, - [89] = KEY_KP3, - [90] = KEY_KP0, - [91] = KEY_KPDOT, - [94] = KEY_102ND, /* FIXME is this correct? */ - [95] = KEY_F11, - [96] = KEY_F12, - [108] = KEY_KPENTER, - [109] = KEY_RIGHTCTRL, - [112] = KEY_KPSLASH, - [111] = KEY_SYSRQ, - [113] = KEY_RIGHTALT, - [97] = KEY_HOME, - [98] = KEY_UP, - [99] = KEY_PAGEUP, - [100] = KEY_LEFT, - [102] = KEY_RIGHT, - [103] = KEY_END, - [104] = KEY_DOWN, - [105] = KEY_PAGEDOWN, - [106] = KEY_INSERT, - [107] = KEY_DELETE, - [110] = KEY_PAUSE, - [115] = KEY_LEFTMETA, - [116] = KEY_RIGHTMETA, - [117] = KEY_MENU, -}; - -static int btnmap[] = { - [SDL_BUTTON_LEFT] = BTN_LEFT, - [SDL_BUTTON_MIDDLE] = BTN_MIDDLE, - [SDL_BUTTON_RIGHT] = BTN_RIGHT, - /* FIXME not 100% sure about these: */ - [SDL_BUTTON_WHEELUP] = BTN_FORWARD, - [SDL_BUTTON_WHEELDOWN] BTN_BACK -}; - -static void sdl_update(struct xenfb *xenfb, int x, int y, int width, int height) -{ - struct SDLFBData *data = xenfb->user_data; - SDL_Rect r = { x, y, width, height }; - SDL_BlitSurface(data->src, &r, data->dst, &r); - SDL_UpdateRect(data->dst, x, y, width, height); -} - -static int sdl_on_event(struct xenfb *xenfb, SDL_Event *event) -{ - int x, y, ret; - - switch (event->type) { - case SDL_KEYDOWN: - case SDL_KEYUP: - if (keymap[event->key.keysym.scancode] == 0) - break; - ret = xenfb_send_key(xenfb, - event->type == SDL_KEYDOWN, - keymap[event->key.keysym.scancode]); - if (ret < 0) - fprintf(stderr, "Key %d %s lost (%s)\n", - keymap[event->key.keysym.scancode], - event->type == SDL_KEYDOWN ? "down" : "up", - strerror(errno)); - break; - case SDL_MOUSEMOTION: - if (xenfb->abs_pointer_wanted) { - SDL_GetMouseState(&x, &y); - ret = xenfb_send_position(xenfb, x, y); - } else { - SDL_GetRelativeMouseState(&x, &y); - ret = xenfb_send_motion(xenfb, x, y); - } - if (ret < 0) - fprintf(stderr, "Pointer to %d,%d lost (%s)\n", - x, y, strerror(errno)); - break; - case SDL_MOUSEBUTTONDOWN: - case SDL_MOUSEBUTTONUP: - if (event->button.button >= sizeof(btnmap) / sizeof(*btnmap)) - break; - if (btnmap[event->button.button] == 0) - break; - ret = xenfb_send_key(xenfb, - event->type == SDL_MOUSEBUTTONDOWN, - btnmap[event->button.button]); - if (ret < 0) - fprintf(stderr, "Button %d %s lost (%s)\n", - btnmap[event->button.button] - BTN_MOUSE, - event->type == SDL_MOUSEBUTTONDOWN ? "down" : "up", - strerror(errno)); - break; - case SDL_QUIT: - return 0; - } - - return 1; -} - -static struct option options[] = { - { "domid", 1, NULL, ''d'' }, - { "title", 1, NULL, ''t'' }, - { NULL } -}; - -int main(int argc, char **argv) -{ - struct xenfb *xenfb; - int domid = -1; - char * title = NULL; - fd_set readfds; - int nfds; - struct SDLFBData data; - SDL_Rect r; - struct timeval tv; - SDL_Event event; - int do_quit = 0; - int opt; - char *endp; - int retval; - - while ((opt = getopt_long(argc, argv, "d:t:", options, - NULL)) != -1) { - switch (opt) { - case ''d'': - domid = strtol(optarg, &endp, 10); - if (endp == optarg || *endp) { - fprintf(stderr, "Invalid domain id specified\n"); - exit(1); - } - break; - case ''t'': - title = strdup(optarg); - break; - case ''?'': - exit(1); - } - } - if (optind != argc) { - fprintf(stderr, "Invalid options!\n"); - exit(1); - } - if (domid <= 0) { - fprintf(stderr, "Domain ID must be specified!\n"); - exit(1); - } - - xenfb = xenfb_new(); - if (xenfb == NULL) { - fprintf(stderr, "Could not create framebuffer (%s)\n", - strerror(errno)); - exit(1); - } - - if (xenfb_attach_dom(xenfb, domid) < 0) { - fprintf(stderr, "Could not connect to domain (%s)\n", - strerror(errno)); - exit(1); - } - - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - fprintf(stderr, "Could not initialize SDL\n"); - exit(1); - } - - data.dst = SDL_SetVideoMode(xenfb->width, xenfb->height, xenfb->depth, - SDL_SWSURFACE); - if (!data.dst) { - fprintf(stderr, "SDL_SetVideoMode failed\n"); - exit(1); - } - - data.src = SDL_CreateRGBSurfaceFrom(xenfb->pixels, - xenfb->width, xenfb->height, - xenfb->depth, xenfb->row_stride, - 0xFF0000, 0xFF00, 0xFF, 0); - - if (!data.src) { - fprintf(stderr, "SDL_CreateRGBSurfaceFrom failed\n"); - exit(1); - } - - if (title == NULL) - title = strdup("xen-sdlfb"); - SDL_WM_SetCaption(title, title); - - r.x = r.y = 0; - r.w = xenfb->width; - r.h = xenfb->height; - SDL_BlitSurface(data.src, &r, data.dst, &r); - SDL_UpdateRect(data.dst, 0, 0, xenfb->width, xenfb->height); - - xenfb->update = sdl_update; - xenfb->user_data = &data; - - SDL_ShowCursor(0); - - /* - * We need to wait for fds becoming ready or SDL events to - * arrive. We time out the select after 10ms to poll for SDL - * events. Clunky, but works. Could avoid the clunkiness - * with a separate thread. - */ - for (;;) { - FD_ZERO(&readfds); - nfds = xenfb_select_fds(xenfb, &readfds); - tv = (struct timeval){0, 10000}; - - if (select(nfds, &readfds, NULL, NULL, &tv) < 0) { - if (errno == EINTR) - continue; - fprintf(stderr, - "Can''t select() on event channel (%s)\n", - strerror(errno)); - break; - } - - while (SDL_PollEvent(&event)) { - if (!sdl_on_event(xenfb, &event)) - do_quit = 1; - } - - if (do_quit) - break; - - retval = xenfb_poll(xenfb, &readfds); - if (retval == -2) - xenfb_teardown(xenfb); - if (retval < 0) - break; - } - - xenfb_delete(xenfb); - - SDL_Quit(); - - return 0; -} diff -r 450e0143acaf tools/xenfb/vncfb.c --- a/tools/xenfb/vncfb.c Tue Aug 14 14:31:01 2007 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,522 +0,0 @@ -#define _GNU_SOURCE -#include <errno.h> -#include <getopt.h> -#include <stdlib.h> -#include <signal.h> -#include <unistd.h> -#include <malloc.h> -#include <rfb/rfb.h> -#include <rfb/keysym.h> -#include <linux/input.h> -#include <xs.h> -#include "xenfb.h" - -/* Grab key translation support routines from qemu directory. */ -#define qemu_mallocz(size) calloc(1, (size)) -static const char *bios_dir = "/usr/share/xen/qemu"; -#include "vnc_keysym.h" -#include "keymaps.c" - -static unsigned char atkbd_set2_keycode[512] = { - - 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41,117, - 0, 56, 42, 93, 29, 16, 2, 0, 0, 0, 44, 31, 30, 17, 3, 0, - 0, 46, 45, 32, 18, 5, 4, 95, 0, 57, 47, 33, 20, 19, 6,183, - 0, 49, 48, 35, 34, 21, 7,184, 0, 0, 50, 36, 22, 8, 9,185, - 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0, - 0, 89, 40, 0, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 85, - 0, 86, 91, 90, 92, 0, 14, 94, 0, 79,124, 75, 71,121, 0, 0, - 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99, - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 217,100,255, 0, 97,165, 0, 0,156, 0, 0, 0, 0, 0, 0,125, - 173,114, 0,113, 0, 0, 0,126,128, 0, 0,140, 0, 0, 0,127, - 159, 0,115, 0,164, 0, 0,116,158, 0,150,166, 0, 0, 0,142, - 157, 0, 0, 0, 0, 0, 0, 0,155, 0, 98, 0, 0,163, 0, 0, - 226, 0, 0, 0, 0, 0, 0, 0, 0,255, 96, 0, 0, 0,143, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,107, 0,105,102, 0, 0,112, - 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119, 0, - -}; - -static unsigned char atkbd_unxlate_table[128] = { - - 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13, - 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27, - 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42, - 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3, - 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105, - 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63, - 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111, - 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110 - -}; - -unsigned char keycode_table[512]; - -static void *kbd_layout; -uint8_t modifiers_state[256]; - -static int btnmap[] = { - BTN_LEFT, BTN_MIDDLE, BTN_RIGHT, BTN_SIDE, - BTN_EXTRA, BTN_FORWARD, BTN_BACK, BTN_TASK -}; - -static void press_key_shift_down(struct xenfb* xenfb, int down, int scancode) -{ - if (down) - xenfb_send_key(xenfb, 1, keycode_table[0x2a]); - - if (xenfb_send_key(xenfb, down, keycode_table[scancode]) < 0) - fprintf(stderr, "Key %d %s lost (%s)\n", - scancode, "down", strerror(errno)); - - if (!down) - xenfb_send_key(xenfb, 0, keycode_table[0x2a]); -} - -static void press_key_shift_up(struct xenfb* xenfb, int down, int scancode) -{ - if (down) { - if (modifiers_state[0x2a]) - xenfb_send_key(xenfb, 0, keycode_table[0x2a]); - if (modifiers_state[0x36]) - xenfb_send_key(xenfb, 0, keycode_table[0x36]); - } - - if (xenfb_send_key(xenfb, down, keycode_table[scancode]) < 0) - fprintf(stderr, "Key %d %s lost (%s)\n", - scancode, "down", strerror(errno)); - - if (!down) { - if (modifiers_state[0x2a]) - xenfb_send_key(xenfb, 1, keycode_table[0x2a]); - if (modifiers_state[0x36]) - xenfb_send_key(xenfb, 1, keycode_table[0x36]); - } -} - -static void on_kbd_event(rfbBool down, rfbKeySym keycode, rfbClientPtr cl) -{ - /* - * We need to map to the key''s Linux input layer keycode. - * Unfortunately, we don''t get the key here, only the - * rfbKeySym, which is what the key is mapped to. Mapping - * back to the key is impossible in general, even when you - * know the keymap. For instance, the standard German keymap - * maps both KEY_COMMA and KEY_102ND to XK_less. We simply - * assume standard US layout. This sucks. - */ - rfbScreenInfoPtr server = cl->screen; - struct xenfb *xenfb = server->screenData; - int scancode; - int shift = 0; - int shift_keys = 0; - - if (keycode >= ''A'' && keycode <= ''Z'') { - keycode += ''a'' - ''A''; - shift = 1; - } - else { - shift = keysymIsShift(kbd_layout, keycode); - } - shift_keys = modifiers_state[0x2a] | modifiers_state[0x36]; - - scancode = keysym2scancode(kbd_layout, keycode); - if (scancode == 0) - return; - - switch(scancode) { - case 0x2a: /* Left Shift */ - case 0x36: /* Right Shift */ - case 0x1d: /* Left CTRL */ - case 0x9d: /* Right CTRL */ - case 0x38: /* Left ALT */ - case 0xb8: /* Right ALT */ - if (down) - modifiers_state[scancode] = 1; - else - modifiers_state[scancode] = 0; - xenfb_send_key(xenfb, down, keycode_table[scancode]); - return; - case 0x45: /* NumLock */ - if (!down) - modifiers_state[scancode] ^= 1; - xenfb_send_key(xenfb, down, keycode_table[scancode]); - return; - } - - if (keycodeIsKeypad(kbd_layout, scancode)) { - /* If the numlock state needs to change then simulate an additional - keypress before sending this one. This will happen if the user - toggles numlock away from the VNC window. - */ - if (keysymIsNumlock(kbd_layout, keycode)) { - if (!modifiers_state[0x45]) { - modifiers_state[0x45] = 1; - xenfb_send_key(xenfb, 1, keycode_table[0x45]); - xenfb_send_key(xenfb, 0, keycode_table[0x45]); - } - } else { - if (modifiers_state[0x45]) { - modifiers_state[0x45] = 0; - xenfb_send_key(xenfb, 1, keycode_table[0x45]); - xenfb_send_key(xenfb, 0, keycode_table[0x45]); - } - } - } - - /* If the shift state needs to change then simulate an additional - keypress before sending this one. - */ - if (shift && !shift_keys) { - press_key_shift_down(xenfb, down, scancode); - return; - } - else if (!shift && shift_keys) { - press_key_shift_up(xenfb, down, scancode); - return; - } - - if (xenfb_send_key(xenfb, down, keycode_table[scancode]) < 0) - fprintf(stderr, "Key %d %s lost (%s)\n", - scancode, down ? "down" : "up", - strerror(errno)); -} - -static void on_ptr_event(int buttonMask, int x, int y, rfbClientPtr cl) -{ - /* initial pointer state: at (0,0), buttons up */ - static int last_x, last_y, last_button; - rfbScreenInfoPtr server = cl->screen; - struct xenfb *xenfb = server->screenData; - int i, last_down, down, ret; - - for (i = 0; i < 8; i++) { - last_down = last_button & (1 << i); - down = buttonMask & (1 << i); - if (down == last_down) - continue; - if (i >= sizeof(btnmap) / sizeof(*btnmap)) - break; - if (btnmap[i] == 0) - break; - if (xenfb_send_key(xenfb, down != 0, btnmap[i]) < 0) - fprintf(stderr, "Button %d %s lost (%s)\n", - i, down ? "down" : "up", strerror(errno)); - } - - if (x != last_x || y != last_y) { - if (xenfb->abs_pointer_wanted) - ret = xenfb_send_position(xenfb, x, y); - else - ret = xenfb_send_motion(xenfb, x - last_x, y - last_y); - if (ret < 0) - fprintf(stderr, "Pointer to %d,%d lost (%s)\n", - x, y, strerror(errno)); - } - - last_button = buttonMask; - last_x = x; - last_y = y; -} - -static void xenstore_write_vncport(struct xs_handle *xsh, int port, int domid) -{ - char *buf, *path; - char portstr[10]; - - path = xs_get_domain_path(xsh, domid); - if (path == NULL) { - fprintf(stderr, "Can''t get domain path (%s)\n", - strerror(errno)); - goto out; - } - - if (asprintf(&buf, "%s/console/vnc-port", path) == -1) { - fprintf(stderr, "Can''t make vncport path\n"); - goto out; - } - - if (snprintf(portstr, sizeof(portstr), "%d", port) == -1) { - fprintf(stderr, "Can''t make vncport value\n"); - goto out; - } - - if (!xs_write(xsh, XBT_NULL, buf, portstr, strlen(portstr))) - fprintf(stderr, "Can''t set vncport (%s)\n", - strerror(errno)); - - out: - free(buf); -} - - -static int xenstore_read_vncpasswd(struct xs_handle *xsh, int domid, char *pwbuf, int pwbuflen) -{ - char buf[256], *path, *uuid = NULL, *passwd = NULL; - unsigned int len, rc = 0; - - if (xsh == NULL) { - return -1; - } - - path = xs_get_domain_path(xsh, domid); - if (path == NULL) { - fprintf(stderr, "xs_get_domain_path() error\n"); - return -1; - } - - snprintf(buf, 256, "%s/vm", path); - uuid = xs_read(xsh, XBT_NULL, buf, &len); - if (uuid == NULL) { - fprintf(stderr, "xs_read(): uuid get error\n"); - free(path); - return -1; - } - - snprintf(buf, 256, "%s/vncpasswd", uuid); - passwd = xs_read(xsh, XBT_NULL, buf, &len); - if (passwd == NULL) { - free(uuid); - free(path); - return rc; - } - - strncpy(pwbuf, passwd, pwbuflen-1); - pwbuf[pwbuflen-1] = ''\0''; - - fprintf(stderr, "Got a VNC password read from XenStore\n"); - - passwd[0] = ''\0''; - snprintf(buf, 256, "%s/vncpasswd", uuid); - if (xs_write(xsh, XBT_NULL, buf, passwd, len) == 0) { - fprintf(stderr, "xs_write() vncpasswd failed\n"); - rc = -1; - } - - free(passwd); - free(uuid); - free(path); - - return rc; -} - -static void vnc_update(struct xenfb *xenfb, int x, int y, int w, int h) -{ - rfbScreenInfoPtr server = xenfb->user_data; - rfbMarkRectAsModified(server, x, y, x + w, y + h); -} - -static struct option options[] = { - { "domid", 1, NULL, ''d'' }, - { "vncport", 1, NULL, ''p'' }, - { "title", 1, NULL, ''t'' }, - { "unused", 0, NULL, ''u'' }, - { "listen", 1, NULL, ''l'' }, - { "keymap", 1, NULL, ''k'' }, - { NULL } -}; - -int main(int argc, char **argv) -{ - rfbScreenInfoPtr server; - char *fake_argv[7] = { "vncfb", "-rfbport", "5901", - "-desktop", "xen-vncfb", - "-listen", "127.0.0.1" }; - int fake_argc = sizeof(fake_argv) / sizeof(fake_argv[0]); - int domid = -1, port = -1; - char *title = NULL; - char *listen = NULL; - char *keymap = NULL; - bool unused = false; - int opt; - struct xenfb *xenfb; - fd_set readfds; - int nfds; - char portstr[10]; - char *endp; - int r; - struct xs_handle *xsh; - char vncpasswd[1024]; - int i; - - vncpasswd[0] = ''\0''; - - while ((opt = getopt_long(argc, argv, "d:p:t:uk:", options, - NULL)) != -1) { - switch (opt) { - case ''d'': - errno = 0; - domid = strtol(optarg, &endp, 10); - if (endp == optarg || *endp || errno) { - fprintf(stderr, "Invalid domain id specified\n"); - exit(1); - } - break; - case ''p'': - errno = 0; - port = strtol(optarg, &endp, 10); - if (endp == optarg || *endp || errno) { - fprintf(stderr, "Invalid port specified\n"); - exit(1); - } - break; - case ''t'': - title = strdup(optarg); - break; - case ''u'': - unused = true; - break; - case ''l'': - listen = strdup(optarg); - break; - case ''k'': - keymap = strdup(optarg); - break; - case ''?'': - exit(1); - } - } - if (optind != argc) { - fprintf(stderr, "Invalid options!\n"); - exit(1); - } - if (domid <= 0) { - fprintf(stderr, "Domain ID must be specified!\n"); - exit(1); - } - - if (port <= 0) - port = 5900 + domid; - if (snprintf(portstr, sizeof(portstr), "%d", port) == -1) { - fprintf(stderr, "Invalid port specified\n"); - exit(1); - } - - if (keymap == NULL){ - keymap = "en-us"; - } - - kbd_layout = init_keyboard_layout(keymap); - if( !kbd_layout ){ - fprintf(stderr, "Invalid keyboard_layout\n"); - exit(1); - } - - for (i = 0; i < 128; i++) { - keycode_table[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]]; - keycode_table[i | 0x80] = - atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80]; - } - - for (i = 0; i < 256; i++ ) { - modifiers_state[i] = 0; - } - - fake_argv[2] = portstr; - - if (title != NULL) - fake_argv[4] = title; - - if (listen != NULL) - fake_argv[6] = listen; - - signal(SIGPIPE, SIG_IGN); - - xenfb = xenfb_new(); - if (xenfb == NULL) { - fprintf(stderr, "Could not create framebuffer (%s)\n", - strerror(errno)); - exit(1); - } - - if (xenfb_attach_dom(xenfb, domid) < 0) { - fprintf(stderr, "Could not connect to domain (%s)\n", - strerror(errno)); - exit(1); - } - - xsh = xs_daemon_open(); - if (xsh == NULL) { - fprintf(stderr, "cannot open connection to xenstore\n"); - exit(1); - } - - - if (xenstore_read_vncpasswd(xsh, domid, vncpasswd, - sizeof(vncpasswd)/sizeof(char)) < 0) { - fprintf(stderr, "cannot read VNC password from xenstore\n"); - exit(1); - } - - - server = rfbGetScreen(&fake_argc, fake_argv, - xenfb->width, xenfb->height, - 8, 3, xenfb->depth / 8); - if (server == NULL) { - fprintf(stderr, "Could not create VNC server\n"); - exit(1); - } - - xenfb->user_data = server; - xenfb->update = vnc_update; - - if (unused) - server->autoPort = true; - - if (vncpasswd[0]) { - char **passwds = malloc(sizeof(char**)*2); - if (!passwds) { - fprintf(stderr, "cannot allocate memory (%s)\n", - strerror(errno)); - exit(1); - } - fprintf(stderr, "Registered password\n"); - passwds[0] = vncpasswd; - passwds[1] = NULL; - - server->authPasswdData = passwds; - server->passwordCheck = rfbCheckPasswordByList; - } else { - fprintf(stderr, "Running with no password\n"); - } - server->serverFormat.redShift = 16; - server->serverFormat.greenShift = 8; - server->serverFormat.blueShift = 0; - server->kbdAddEvent = on_kbd_event; - server->ptrAddEvent = on_ptr_event; - server->frameBuffer = xenfb->pixels; - server->screenData = xenfb; - server->cursor = NULL; - rfbInitServer(server); - - rfbRunEventLoop(server, -1, true); - - xenstore_write_vncport(xsh, server->port, domid); - - for (;;) { - FD_ZERO(&readfds); - nfds = xenfb_select_fds(xenfb, &readfds); - - if (select(nfds, &readfds, NULL, NULL, NULL) < 0) { - if (errno == EINTR) - continue; - fprintf(stderr, - "Can''t select() on event channel (%s)\n", - strerror(errno)); - break; - } - - r = xenfb_poll(xenfb, &readfds); - if (r == -2) - xenfb_teardown(xenfb); - if (r < 0) - break; - } - - rfbScreenCleanup(server); - xenfb_delete(xenfb); - - return 0; -} diff -r 450e0143acaf tools/xenfb/xenfb.c --- a/tools/xenfb/xenfb.c Tue Aug 14 14:31:01 2007 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,825 +0,0 @@ -#include <stdarg.h> -#include <stdlib.h> -#include <sys/types.h> -#include <fcntl.h> -#include <unistd.h> -#include <xenctrl.h> -#include <xen/io/xenbus.h> -#include <xen/io/fbif.h> -#include <xen/io/kbdif.h> -#include <xen/io/protocols.h> -#include <sys/select.h> -#include <stdbool.h> -#include <xen/event_channel.h> -#include <sys/mman.h> -#include <errno.h> -#include <stdio.h> -#include <string.h> -#include <time.h> -#include <xs.h> - -#include "xenfb.h" - -// FIXME defend against malicious frontend? - -struct xenfb_device { - const char *devicetype; - char nodename[64]; /* backend xenstore dir */ - char otherend[64]; /* frontend xenstore dir */ - int otherend_id; /* frontend domid */ - enum xenbus_state state; /* backend state */ - void *page; /* shared page */ - evtchn_port_t port; - struct xenfb_private *xenfb; -}; - -struct xenfb_private { - struct xenfb pub; - int evt_xch; /* event channel driver handle */ - int xc; /* hypervisor interface handle */ - struct xs_handle *xsh; /* xs daemon handle */ - struct xenfb_device fb, kbd; - size_t fb_len; /* size of framebuffer */ - char protocol[64]; /* frontend protocol */ -}; - -static void xenfb_detach_dom(struct xenfb_private *); - -static char *xenfb_path_in_dom(struct xs_handle *xsh, - char *buf, size_t size, - unsigned domid, const char *fmt, ...) -{ - va_list ap; - char *domp = xs_get_domain_path(xsh, domid); - int n; - - if (domp == NULL) - return NULL; - - n = snprintf(buf, size, "%s/", domp); - free(domp); - if (n >= size) - return NULL; - - va_start(ap, fmt); - n += vsnprintf(buf + n, size - n, fmt, ap); - va_end(ap); - if (n >= size) - return NULL; - - return buf; -} - -static int xenfb_xs_scanf1(struct xs_handle *xsh, - const char *dir, const char *node, - const char *fmt, void *dest) -{ - char buf[1024]; - char *p; - int ret; - - if (snprintf(buf, sizeof(buf), "%s/%s", dir, node) >= sizeof(buf)) { - errno = ENOENT; - return -1; - } - p = xs_read(xsh, XBT_NULL, buf, NULL); - if (!p) { - errno = ENOENT; - return -1; - } - ret = sscanf(p, fmt, dest); - free(p); - if (ret != 1) { - errno = EDOM; - return -1; - } - return ret; -} - -static int xenfb_xs_printf(struct xs_handle *xsh, - const char *dir, const char *node, char *fmt, ...) -{ - va_list ap; - char key[1024]; - char val[1024]; - int n; - - if (snprintf(key, sizeof(key), "%s/%s", dir, node) >= sizeof(key)) { - errno = ENOENT; - return -1; - } - - va_start(ap, fmt); - n = vsnprintf(val, sizeof(val), fmt, ap); - va_end(ap); - if (n >= sizeof(val)) { - errno = ENOSPC; /* close enough */ - return -1; - } - - if (!xs_write(xsh, XBT_NULL, key, val, n)) - return -1; - return 0; -} - -static void xenfb_device_init(struct xenfb_device *dev, - const char *type, - struct xenfb_private *xenfb) -{ - dev->devicetype = type; - dev->otherend_id = -1; - dev->port = -1; - dev->xenfb = xenfb; -} - -int xenfb_device_set_domain(struct xenfb_device *dev, int domid) -{ - struct xenfb_private *xenfb = dev->xenfb; - - dev->otherend_id = domid; - - if (!xenfb_path_in_dom(xenfb->xsh, - dev->otherend, sizeof(dev->otherend), - domid, "device/%s/0", dev->devicetype)) { - errno = ENOENT; - return -1; - } - if (!xenfb_path_in_dom(xenfb->xsh, - dev->nodename, sizeof(dev->nodename), - 0, "backend/%s/%d/0", dev->devicetype, domid)) { - errno = ENOENT; - return -1; - } - - return 0; -} - -struct xenfb *xenfb_new(void) -{ - struct xenfb_private *xenfb = malloc(sizeof(*xenfb)); - int serrno; - - if (xenfb == NULL) - return NULL; - - memset(xenfb, 0, sizeof(*xenfb)); - xenfb->evt_xch = xenfb->xc = -1; - xenfb_device_init(&xenfb->fb, "vfb", xenfb); - xenfb_device_init(&xenfb->kbd, "vkbd", xenfb); - - xenfb->evt_xch = xc_evtchn_open(); - if (xenfb->evt_xch == -1) - goto fail; - - xenfb->xc = xc_interface_open(); - if (xenfb->xc == -1) - goto fail; - - xenfb->xsh = xs_daemon_open(); - if (!xenfb->xsh) - goto fail; - - return &xenfb->pub; - - fail: - serrno = errno; - xenfb_delete(&xenfb->pub); - errno = serrno; - return NULL; -} - -/* Remove the backend area in xenbus since the framebuffer really is - going away. */ -void xenfb_teardown(struct xenfb *xenfb_pub) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - - xs_rm(xenfb->xsh, XBT_NULL, xenfb->fb.nodename); - xs_rm(xenfb->xsh, XBT_NULL, xenfb->kbd.nodename); -} - - -void xenfb_delete(struct xenfb *xenfb_pub) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - - xenfb_detach_dom(xenfb); - if (xenfb->xc >= 0) - xc_interface_close(xenfb->xc); - if (xenfb->evt_xch >= 0) - xc_evtchn_close(xenfb->evt_xch); - if (xenfb->xsh) - xs_daemon_close(xenfb->xsh); - free(xenfb); -} - -static enum xenbus_state xenfb_read_state(struct xs_handle *xsh, - const char *dir) -{ - int ret, state; - - ret = xenfb_xs_scanf1(xsh, dir, "state", "%d", &state); - if (ret < 0) - return XenbusStateUnknown; - - if ((unsigned)state > XenbusStateClosed) - state = XenbusStateUnknown; - return state; -} - -static int xenfb_switch_state(struct xenfb_device *dev, - enum xenbus_state state) -{ - struct xs_handle *xsh = dev->xenfb->xsh; - - if (xenfb_xs_printf(xsh, dev->nodename, "state", "%d", state) < 0) - return -1; - dev->state = state; - return 0; -} - -static int xenfb_wait_for_state(struct xs_handle *xsh, const char *dir, - unsigned awaited) -{ - unsigned state, dummy; - char **vec; - - awaited |= 1 << XenbusStateUnknown; - - for (;;) { - state = xenfb_read_state(xsh, dir); - if ((1 << state) & awaited) - return state; - - vec = xs_read_watch(xsh, &dummy); - if (!vec) - return -1; - free(vec); - } -} - -static int xenfb_wait_for_backend_creation(struct xenfb_device *dev) -{ - struct xs_handle *xsh = dev->xenfb->xsh; - int state; - - if (!xs_watch(xsh, dev->nodename, "")) - return -1; - state = xenfb_wait_for_state(xsh, dev->nodename, - (1 << XenbusStateInitialising) - | (1 << XenbusStateClosed) -#if 1 /* TODO fudging state to permit restarting; to be removed */ - | (1 << XenbusStateInitWait) - | (1 << XenbusStateConnected) - | (1 << XenbusStateClosing) -#endif - ); - xs_unwatch(xsh, dev->nodename, ""); - - switch (state) { -#if 1 - case XenbusStateInitWait: - case XenbusStateConnected: - printf("Fudging state to %d\n", XenbusStateInitialising); /* FIXME */ -#endif - case XenbusStateInitialising: - case XenbusStateClosing: - case XenbusStateClosed: - break; - default: - return -1; - } - - return 0; -} - -static int xenfb_hotplug(struct xenfb_device *dev) -{ - if (xenfb_xs_printf(dev->xenfb->xsh, dev->nodename, - "hotplug-status", "connected")) - return -1; - return 0; -} - -static int xenfb_wait_for_frontend_initialised(struct xenfb_device *dev) -{ - switch (xenfb_wait_for_state(dev->xenfb->xsh, dev->otherend, -#if 1 /* TODO fudging state to permit restarting; to be removed */ - (1 << XenbusStateInitialised) - | (1 << XenbusStateConnected) -#else - 1 << XenbusStateInitialised, -#endif - )) { -#if 1 - case XenbusStateConnected: - printf("Fudging state to %d\n", XenbusStateInitialised); /* FIXME */ -#endif - case XenbusStateInitialised: - break; - default: - return -1; - } - - return 0; -} - -static void xenfb_copy_mfns(int mode, int count, unsigned long *dst, void *src) -{ - uint32_t *src32 = src; - uint64_t *src64 = src; - int i; - - for (i = 0; i < count; i++) - dst[i] = (mode == 32) ? src32[i] : src64[i]; -} - -static int xenfb_map_fb(struct xenfb_private *xenfb, int domid) -{ - struct xenfb_page *page = xenfb->fb.page; - int n_fbmfns; - int n_fbdirs; - unsigned long *pgmfns = NULL; - unsigned long *fbmfns = NULL; - void *map, *pd; - int mode, ret = -1; - - /* default to native */ - pd = page->pd; - mode = sizeof(unsigned long) * 8; - - if (0 == strlen(xenfb->protocol)) { - /* - * Undefined protocol, some guesswork needed. - * - * Old frontends which don''t set the protocol use - * one page directory only, thus pd[1] must be zero. - * pd[1] of the 32bit struct layout and the lower - * 32 bits of pd[0] of the 64bit struct layout have - * the same location, so we can check that ... - */ - uint32_t *ptr32 = NULL; - uint32_t *ptr64 = NULL; -#if defined(__i386__) - ptr32 = (void*)page->pd; - ptr64 = ((void*)page->pd) + 4; -#elif defined(__x86_64__) - ptr32 = ((void*)page->pd) - 4; - ptr64 = (void*)page->pd; -#endif - if (ptr32) { - if (0 == ptr32[1]) { - mode = 32; - pd = ptr32; - } else { - mode = 64; - pd = ptr64; - } - } -#if defined(__x86_64__) - } else if (0 == strcmp(xenfb->protocol, XEN_IO_PROTO_ABI_X86_32)) { - /* 64bit dom0, 32bit domU */ - mode = 32; - pd = ((void*)page->pd) - 4; -#elif defined(__i386__) - } else if (0 == strcmp(xenfb->protocol, XEN_IO_PROTO_ABI_X86_64)) { - /* 32bit dom0, 64bit domU */ - mode = 64; - pd = ((void*)page->pd) + 4; -#endif - } - - n_fbmfns = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE; - n_fbdirs = n_fbmfns * mode / 8; - n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE; - - pgmfns = malloc(sizeof(unsigned long) * n_fbdirs); - fbmfns = malloc(sizeof(unsigned long) * n_fbmfns); - if (!pgmfns || !fbmfns) - goto out; - - /* - * Bug alert: xc_map_foreign_batch() can fail partly and - * return a non-null value. This is a design flaw. When it - * happens, we happily continue here, and later crash on - * access. - */ - xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd); - map = xc_map_foreign_batch(xenfb->xc, domid, - PROT_READ, pgmfns, n_fbdirs); - if (map == NULL) - goto out; - xenfb_copy_mfns(mode, n_fbmfns, fbmfns, map); - munmap(map, n_fbdirs * XC_PAGE_SIZE); - - xenfb->pub.pixels = xc_map_foreign_batch(xenfb->xc, domid, - PROT_READ | PROT_WRITE, fbmfns, n_fbmfns); - if (xenfb->pub.pixels == NULL) - goto out; - - ret = 0; /* all is fine */ - - out: - if (pgmfns) - free(pgmfns); - if (fbmfns) - free(fbmfns); - return ret; -} - -static int xenfb_bind(struct xenfb_device *dev) -{ - struct xenfb_private *xenfb = dev->xenfb; - unsigned long mfn; - evtchn_port_t evtchn; - - if (xenfb_xs_scanf1(xenfb->xsh, dev->otherend, "page-ref", "%lu", - &mfn) < 0) - return -1; - if (xenfb_xs_scanf1(xenfb->xsh, dev->otherend, "event-channel", "%u", - &evtchn) < 0) - return -1; - - dev->port = xc_evtchn_bind_interdomain(xenfb->evt_xch, - dev->otherend_id, evtchn); - if (dev->port == -1) - return -1; - - dev->page = xc_map_foreign_range(xenfb->xc, dev->otherend_id, - XC_PAGE_SIZE, PROT_READ | PROT_WRITE, mfn); - if (dev->page == NULL) - return -1; - - return 0; -} - -static void xenfb_unbind(struct xenfb_device *dev) -{ - if (dev->page) { - munmap(dev->page, XC_PAGE_SIZE); - dev->page = NULL; - } - if (dev->port >= 0) { - xc_evtchn_unbind(dev->xenfb->evt_xch, dev->port); - dev->port = -1; - } -} - -static int xenfb_wait_for_frontend_connected(struct xenfb_device *dev) -{ - switch (xenfb_wait_for_state(dev->xenfb->xsh, dev->otherend, - 1 << XenbusStateConnected)) { - case XenbusStateConnected: - break; - default: - return -1; - } - - return 0; -} - -static void xenfb_dev_fatal(struct xenfb_device *dev, int err, - const char *fmt, ...) -{ - struct xs_handle *xsh = dev->xenfb->xsh; - va_list ap; - char errdir[80]; - char buf[1024]; - int n; - - fprintf(stderr, "%s ", dev->nodename); /* somewhat crude */ - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - if (err) - fprintf(stderr, " (%s)", strerror(err)); - putc(''\n'', stderr); - - if (!xenfb_path_in_dom(xsh, errdir, sizeof(errdir), 0, - "error/%s", dev->nodename)) - goto out; /* FIXME complain */ - - va_start(ap, fmt); - n = snprintf(buf, sizeof(buf), "%d ", err); - snprintf(buf + n, sizeof(buf) - n, fmt, ap); - va_end(ap); - - if (xenfb_xs_printf(xsh, buf, "error", "%s", buf) < 0) - goto out; /* FIXME complain */ - - out: - xenfb_switch_state(dev, XenbusStateClosing); -} - -int xenfb_attach_dom(struct xenfb *xenfb_pub, int domid) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - struct xs_handle *xsh = xenfb->xsh; - int val, serrno; - struct xenfb_page *fb_page; - - xenfb_detach_dom(xenfb); - - xenfb_device_set_domain(&xenfb->fb, domid); - xenfb_device_set_domain(&xenfb->kbd, domid); - - if (xenfb_wait_for_backend_creation(&xenfb->fb) < 0) - goto error; - if (xenfb_wait_for_backend_creation(&xenfb->kbd) < 0) - goto error; - - if (xenfb_xs_printf(xsh, xenfb->kbd.nodename, "feature-abs-pointer", "1")) - goto error; - if (xenfb_switch_state(&xenfb->fb, XenbusStateInitWait)) - goto error; - if (xenfb_switch_state(&xenfb->kbd, XenbusStateInitWait)) - goto error; - - if (xenfb_hotplug(&xenfb->fb) < 0) - goto error; - if (xenfb_hotplug(&xenfb->kbd) < 0) - goto error; - - if (!xs_watch(xsh, xenfb->fb.otherend, "")) - goto error; - if (!xs_watch(xsh, xenfb->kbd.otherend, "")) - goto error; - - if (xenfb_wait_for_frontend_initialised(&xenfb->fb) < 0) - goto error; - if (xenfb_wait_for_frontend_initialised(&xenfb->kbd) < 0) - goto error; - - if (xenfb_bind(&xenfb->fb) < 0) - goto error; - if (xenfb_bind(&xenfb->kbd) < 0) - goto error; - - if (xenfb_xs_scanf1(xsh, xenfb->fb.otherend, "feature-update", - "%d", &val) < 0) - val = 0; - if (!val) { - errno = ENOTSUP; - goto error; - } - if (xenfb_xs_scanf1(xsh, xenfb->fb.otherend, "protocol", "%63s", - xenfb->protocol) < 0) - xenfb->protocol[0] = ''\0''; - xenfb_xs_printf(xsh, xenfb->fb.nodename, "request-update", "1"); - - /* TODO check for permitted ranges */ - fb_page = xenfb->fb.page; - xenfb->pub.depth = fb_page->depth; - xenfb->pub.width = fb_page->width; - xenfb->pub.height = fb_page->height; - /* TODO check for consistency with the above */ - xenfb->fb_len = fb_page->mem_length; - xenfb->pub.row_stride = fb_page->line_length; - - if (xenfb_map_fb(xenfb, domid) < 0) - goto error; - - if (xenfb_switch_state(&xenfb->fb, XenbusStateConnected)) - goto error; - if (xenfb_switch_state(&xenfb->kbd, XenbusStateConnected)) - goto error; - - if (xenfb_wait_for_frontend_connected(&xenfb->kbd) < 0) - goto error; - if (xenfb_xs_scanf1(xsh, xenfb->kbd.otherend, "request-abs-pointer", - "%d", &val) < 0) - val = 0; - xenfb->pub.abs_pointer_wanted = val; - - return 0; - - error: - serrno = errno; - xenfb_detach_dom(xenfb); - xenfb_dev_fatal(&xenfb->fb, serrno, "on fire"); - xenfb_dev_fatal(&xenfb->kbd, serrno, "on fire"); - errno = serrno; - return -1; -} - -static void xenfb_detach_dom(struct xenfb_private *xenfb) -{ - xenfb_unbind(&xenfb->fb); - xenfb_unbind(&xenfb->kbd); - if (xenfb->pub.pixels) { - munmap(xenfb->pub.pixels, xenfb->fb_len); - xenfb->pub.pixels = NULL; - } -} - -static void xenfb_on_fb_event(struct xenfb_private *xenfb) -{ - uint32_t prod, cons; - struct xenfb_page *page = xenfb->fb.page; - - prod = page->out_prod; - if (prod == page->out_cons) - return; - rmb(); /* ensure we see ring contents up to prod */ - for (cons = page->out_cons; cons != prod; cons++) { - union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons); - - switch (event->type) { - case XENFB_TYPE_UPDATE: - if (xenfb->pub.update) - xenfb->pub.update(&xenfb->pub, - event->update.x, event->update.y, - event->update.width, event->update.height); - break; - } - } - mb(); /* ensure we''re done with ring contents */ - page->out_cons = cons; - xc_evtchn_notify(xenfb->evt_xch, xenfb->fb.port); -} - -static void xenfb_on_kbd_event(struct xenfb_private *xenfb) -{ - struct xenkbd_page *page = xenfb->kbd.page; - - /* We don''t understand any keyboard events, so just ignore them. */ - if (page->out_prod == page->out_cons) - return; - page->out_cons = page->out_prod; - xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port); -} - -static int xenfb_on_state_change(struct xenfb_device *dev) -{ - enum xenbus_state state; - - state = xenfb_read_state(dev->xenfb->xsh, dev->otherend); - - switch (state) { - case XenbusStateUnknown: - /* There was an error reading the frontend state. The - domain has probably gone away; in any case, there''s - not much point in us continuing. */ - return -1; - case XenbusStateInitialising: - case XenbusStateInitWait: - case XenbusStateInitialised: - case XenbusStateConnected: - break; - case XenbusStateClosing: - xenfb_unbind(dev); - xenfb_switch_state(dev, state); - break; - case XenbusStateClosed: - xenfb_switch_state(dev, state); - } - return 0; -} - -int xenfb_dispatch_channel(struct xenfb *xenfb_pub) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - evtchn_port_t port; - port = xc_evtchn_pending(xenfb->evt_xch); - if (port == -1) - return -1; - - if (port == xenfb->fb.port) - xenfb_on_fb_event(xenfb); - else if (port == xenfb->kbd.port) - xenfb_on_kbd_event(xenfb); - - if (xc_evtchn_unmask(xenfb->evt_xch, port) == -1) - return -1; - - return 0; -} - -int xenfb_dispatch_store(struct xenfb *xenfb_pub) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - unsigned dummy; - char **vec; - int r; - - vec = xs_read_watch(xenfb->xsh, &dummy); - free(vec); - r = xenfb_on_state_change(&xenfb->fb); - if (r == 0) - r = xenfb_on_state_change(&xenfb->kbd); - if (r == -1) - return -2; - - return 0; -} - - -/* Returns 0 normally, -1 on error, or -2 if the domain went away. */ -int xenfb_poll(struct xenfb *xenfb_pub, fd_set *readfds) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - int ret; - - if (FD_ISSET(xc_evtchn_fd(xenfb->evt_xch), readfds)) { - if ((ret = xenfb_dispatch_channel(xenfb_pub)) < 0) - return ret; - } - - if (FD_ISSET(xs_fileno(xenfb->xsh), readfds)) { - if ((ret = xenfb_dispatch_store(xenfb_pub)) < 0) - return ret; - } - - return 0; -} - -int xenfb_select_fds(struct xenfb *xenfb_pub, fd_set *readfds) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - int fd1 = xc_evtchn_fd(xenfb->evt_xch); - int fd2 = xs_fileno(xenfb->xsh); - - FD_SET(fd1, readfds); - FD_SET(fd2, readfds); - return fd1 > fd2 ? fd1 + 1 : fd2 + 1; -} - -int xenfb_get_store_fd(struct xenfb *xenfb_pub) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - return xs_fileno(xenfb->xsh); -} - -int xenfb_get_channel_fd(struct xenfb *xenfb_pub) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - return xc_evtchn_fd(xenfb->evt_xch); -} - -static int xenfb_kbd_event(struct xenfb_private *xenfb, - union xenkbd_in_event *event) -{ - uint32_t prod; - struct xenkbd_page *page = xenfb->kbd.page; - - if (xenfb->kbd.state != XenbusStateConnected) - return 0; - - prod = page->in_prod; - if (prod - page->in_cons == XENKBD_IN_RING_LEN) { - errno = EAGAIN; - return -1; - } - - mb(); /* ensure ring space available */ - XENKBD_IN_RING_REF(page, prod) = *event; - wmb(); /* ensure ring contents visible */ - page->in_prod = prod + 1; - return xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port); -} - -int xenfb_send_key(struct xenfb *xenfb_pub, bool down, int keycode) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - union xenkbd_in_event event; - - memset(&event, 0, XENKBD_IN_EVENT_SIZE); - event.type = XENKBD_TYPE_KEY; - event.key.pressed = down ? 1 : 0; - event.key.keycode = keycode; - - return xenfb_kbd_event(xenfb, &event); -} - -int xenfb_send_motion(struct xenfb *xenfb_pub, int rel_x, int rel_y) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - union xenkbd_in_event event; - - memset(&event, 0, XENKBD_IN_EVENT_SIZE); - event.type = XENKBD_TYPE_MOTION; - event.motion.rel_x = rel_x; - event.motion.rel_y = rel_y; - - return xenfb_kbd_event(xenfb, &event); -} - -int xenfb_send_position(struct xenfb *xenfb_pub, int abs_x, int abs_y) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - union xenkbd_in_event event; - - memset(&event, 0, XENKBD_IN_EVENT_SIZE); - event.type = XENKBD_TYPE_POS; - event.pos.abs_x = abs_x; - event.pos.abs_y = abs_y; - - return xenfb_kbd_event(xenfb, &event); -} -/* - * Local variables: - * c-indent-level: 8 - * c-basic-offset: 8 - * tab-width: 8 - * End: - */ diff -r 450e0143acaf tools/xenfb/xenfb.h --- a/tools/xenfb/xenfb.h Tue Aug 14 14:31:01 2007 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -#ifndef _XENFB_H_ -#define _XENFB_H_ - -#include <stdbool.h> -#include <sys/types.h> - -struct xenfb -{ - void *pixels; - - int row_stride; - int depth; - int width; - int height; - int abs_pointer_wanted; - - void *user_data; - - void (*update)(struct xenfb *xenfb, int x, int y, int width, int height); -}; - -struct xenfb *xenfb_new(void); -void xenfb_delete(struct xenfb *xenfb); -void xenfb_teardown(struct xenfb *xenfb); - -int xenfb_attach_dom(struct xenfb *xenfb, int domid); - -int xenfb_dispatch_store(struct xenfb *xenfb_pub); -int xenfb_dispatch_channel(struct xenfb *xenfb_pub); -int xenfb_select_fds(struct xenfb *xenfb, fd_set *readfds); -int xenfb_poll(struct xenfb *xenfb, fd_set *readfds); -int xenfb_get_store_fd(struct xenfb *xenfb_pub); -int xenfb_get_channel_fd(struct xenfb *xenfb_pub); - -int xenfb_send_key(struct xenfb *xenfb, bool down, int keycode); -int xenfb_send_motion(struct xenfb *xenfb, int rel_x, int rel_y); -int xenfb_send_position(struct xenfb *xenfb, int abs_x, int abs_y); - -#endif -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=| _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel P. Berrange
2007-Aug-15 20:06 UTC
Re: [Xen-devel] PATCH: 4/10: Refactor xenfb event handlers
This patch is a simple code re-factoring to move the event loop integration directly into the xenfb.c file. It is to facilitate the patches which follow. xen_machine_pv.c | 29 ------ xenfb.c | 249 +++++++++++++++++++++++-------------------------------- xenfb.h | 7 - 3 files changed, 106 insertions(+), 179 deletions(-) Signed-off-by: Daniel P. Berrange <berrange@redhat.com> Dan. diff -r bd1bddd42929 tools/ioemu/hw/xen_machine_pv.c --- a/tools/ioemu/hw/xen_machine_pv.c Tue Aug 14 14:38:28 2007 -0400 +++ b/tools/ioemu/hw/xen_machine_pv.c Tue Aug 14 15:04:55 2007 -0400 @@ -136,21 +136,6 @@ void xen_pvfb_invalidate(void *opaque) /* Screen dump is not used in Xen, so no need to impl this ? */ void xen_pvfb_screen_dump(void *opaque, const char *name) { } -void xen_pvfb_dispatch_store(void *opaque) { - int ret; - if ((ret = xenfb_dispatch_store((struct xenfb *)opaque)) < 0) { - fprintf(stderr, "Failure while dispatching store: %d\n", ret); - exit(1); - } -} - -void xen_pvfb_dispatch_channel(void *opaque) { - int ret; - if ((ret = xenfb_dispatch_channel((struct xenfb *)opaque)) < 0) { - fprintf(stderr, "Failure while dispatching store: %d\n", ret); - exit(1); - } -} /* The Xen PV machine currently provides * - a virtual framebuffer @@ -165,7 +150,6 @@ static void xen_init_pv(uint64_t ram_siz { struct xenfb *xenfb; extern int domid; - int fd; /* Prepare PVFB state */ xenfb = xenfb_new(); @@ -197,19 +181,6 @@ static void xen_init_pv(uint64_t ram_siz xenfb->abs_pointer_wanted, "Xen PVFB Mouse"); - /* Listen for events from xenstore */ - fd = xenfb_get_store_fd(xenfb); - if (qemu_set_fd_handler2(fd, NULL, xen_pvfb_dispatch_store, NULL, xenfb) < 0) { - fprintf(stderr, "Could not register event handler (%s)\n", - strerror(errno)); - } - - /* Listen for events from the event channel */ - fd = xenfb_get_channel_fd(xenfb); - if (qemu_set_fd_handler2(fd, NULL, xen_pvfb_dispatch_channel, NULL, xenfb) < 0) { - fprintf(stderr, "Could not register event handler (%s)\n", - strerror(errno)); - } /* Setup QEMU display */ dpy_resize(ds, xenfb->width, xenfb->height); diff -r bd1bddd42929 tools/ioemu/hw/xenfb.c --- a/tools/ioemu/hw/xenfb.c Tue Aug 14 14:38:28 2007 -0400 +++ b/tools/ioemu/hw/xenfb.c Tue Aug 14 15:10:27 2007 -0400 @@ -8,7 +8,6 @@ #include <xen/io/fbif.h> #include <xen/io/kbdif.h> #include <xen/io/protocols.h> -#include <sys/select.h> #include <stdbool.h> #include <xen/event_channel.h> #include <sys/mman.h> @@ -18,6 +17,7 @@ #include <time.h> #include <xs.h> +#include "vl.h" #include "xenfb.h" // FIXME defend against malicious frontend? @@ -511,96 +511,6 @@ static void xenfb_dev_fatal(struct xenfb xenfb_switch_state(dev, XenbusStateClosing); } -int xenfb_attach_dom(struct xenfb *xenfb_pub, int domid) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - struct xs_handle *xsh = xenfb->xsh; - int val, serrno; - struct xenfb_page *fb_page; - - xenfb_detach_dom(xenfb); - - xenfb_device_set_domain(&xenfb->fb, domid); - xenfb_device_set_domain(&xenfb->kbd, domid); - - if (xenfb_wait_for_backend_creation(&xenfb->fb) < 0) - goto error; - if (xenfb_wait_for_backend_creation(&xenfb->kbd) < 0) - goto error; - - if (xenfb_xs_printf(xsh, xenfb->kbd.nodename, "feature-abs-pointer", "1")) - goto error; - if (xenfb_switch_state(&xenfb->fb, XenbusStateInitWait)) - goto error; - if (xenfb_switch_state(&xenfb->kbd, XenbusStateInitWait)) - goto error; - - if (xenfb_hotplug(&xenfb->fb) < 0) - goto error; - if (xenfb_hotplug(&xenfb->kbd) < 0) - goto error; - - if (!xs_watch(xsh, xenfb->fb.otherend, "")) - goto error; - if (!xs_watch(xsh, xenfb->kbd.otherend, "")) - goto error; - - if (xenfb_wait_for_frontend_initialised(&xenfb->fb) < 0) - goto error; - if (xenfb_wait_for_frontend_initialised(&xenfb->kbd) < 0) - goto error; - - if (xenfb_bind(&xenfb->fb) < 0) - goto error; - if (xenfb_bind(&xenfb->kbd) < 0) - goto error; - - if (xenfb_xs_scanf1(xsh, xenfb->fb.otherend, "feature-update", - "%d", &val) < 0) - val = 0; - if (!val) { - errno = ENOTSUP; - goto error; - } - if (xenfb_xs_scanf1(xsh, xenfb->fb.otherend, "protocol", "%63s", - xenfb->protocol) < 0) - xenfb->protocol[0] = ''\0''; - xenfb_xs_printf(xsh, xenfb->fb.nodename, "request-update", "1"); - - /* TODO check for permitted ranges */ - fb_page = xenfb->fb.page; - xenfb->pub.depth = fb_page->depth; - xenfb->pub.width = fb_page->width; - xenfb->pub.height = fb_page->height; - /* TODO check for consistency with the above */ - xenfb->fb_len = fb_page->mem_length; - xenfb->pub.row_stride = fb_page->line_length; - - if (xenfb_map_fb(xenfb, domid) < 0) - goto error; - - if (xenfb_switch_state(&xenfb->fb, XenbusStateConnected)) - goto error; - if (xenfb_switch_state(&xenfb->kbd, XenbusStateConnected)) - goto error; - - if (xenfb_wait_for_frontend_connected(&xenfb->kbd) < 0) - goto error; - if (xenfb_xs_scanf1(xsh, xenfb->kbd.otherend, "request-abs-pointer", - "%d", &val) < 0) - val = 0; - xenfb->pub.abs_pointer_wanted = val; - - return 0; - - error: - serrno = errno; - xenfb_detach_dom(xenfb); - xenfb_dev_fatal(&xenfb->fb, serrno, "on fire"); - xenfb_dev_fatal(&xenfb->kbd, serrno, "on fire"); - errno = serrno; - return -1; -} static void xenfb_detach_dom(struct xenfb_private *xenfb) { @@ -676,13 +586,13 @@ static int xenfb_on_state_change(struct return 0; } -int xenfb_dispatch_channel(struct xenfb *xenfb_pub) +static void xenfb_dispatch_channel(void *xenfb_pub) { struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; evtchn_port_t port; port = xc_evtchn_pending(xenfb->evt_xch); if (port == -1) - return -1; + exit(1); if (port == xenfb->fb.port) xenfb_on_fb_event(xenfb); @@ -690,12 +600,10 @@ int xenfb_dispatch_channel(struct xenfb xenfb_on_kbd_event(xenfb); if (xc_evtchn_unmask(xenfb->evt_xch, port) == -1) - return -1; - - return 0; -} - -int xenfb_dispatch_store(struct xenfb *xenfb_pub) + exit(1); +} + +static void xenfb_dispatch_store(void *xenfb_pub) { struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; unsigned dummy; @@ -708,52 +616,107 @@ int xenfb_dispatch_store(struct xenfb *x if (r == 0) r = xenfb_on_state_change(&xenfb->kbd); if (r == -1) - return -2; - - return 0; -} - - -/* Returns 0 normally, -1 on error, or -2 if the domain went away. */ -int xenfb_poll(struct xenfb *xenfb_pub, fd_set *readfds) + exit(1); +} + + +int xenfb_attach_dom(struct xenfb *xenfb_pub, int domid) { struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - int ret; - - if (FD_ISSET(xc_evtchn_fd(xenfb->evt_xch), readfds)) { - if ((ret = xenfb_dispatch_channel(xenfb_pub)) < 0) - return ret; - } - - if (FD_ISSET(xs_fileno(xenfb->xsh), readfds)) { - if ((ret = xenfb_dispatch_store(xenfb_pub)) < 0) - return ret; - } - - return 0; -} - -int xenfb_select_fds(struct xenfb *xenfb_pub, fd_set *readfds) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - int fd1 = xc_evtchn_fd(xenfb->evt_xch); - int fd2 = xs_fileno(xenfb->xsh); - - FD_SET(fd1, readfds); - FD_SET(fd2, readfds); - return fd1 > fd2 ? fd1 + 1 : fd2 + 1; -} - -int xenfb_get_store_fd(struct xenfb *xenfb_pub) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - return xs_fileno(xenfb->xsh); -} - -int xenfb_get_channel_fd(struct xenfb *xenfb_pub) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - return xc_evtchn_fd(xenfb->evt_xch); + struct xs_handle *xsh = xenfb->xsh; + int val, serrno; + struct xenfb_page *fb_page; + + xenfb_detach_dom(xenfb); + + xenfb_device_set_domain(&xenfb->fb, domid); + xenfb_device_set_domain(&xenfb->kbd, domid); + + if (xenfb_wait_for_backend_creation(&xenfb->fb) < 0) + goto error; + if (xenfb_wait_for_backend_creation(&xenfb->kbd) < 0) + goto error; + + if (xenfb_xs_printf(xsh, xenfb->kbd.nodename, "feature-abs-pointer", "1")) + goto error; + if (xenfb_switch_state(&xenfb->fb, XenbusStateInitWait)) + goto error; + if (xenfb_switch_state(&xenfb->kbd, XenbusStateInitWait)) + goto error; + + if (xenfb_hotplug(&xenfb->fb) < 0) + goto error; + if (xenfb_hotplug(&xenfb->kbd) < 0) + goto error; + + if (!xs_watch(xsh, xenfb->fb.otherend, "")) + goto error; + if (!xs_watch(xsh, xenfb->kbd.otherend, "")) + goto error; + + if (xenfb_wait_for_frontend_initialised(&xenfb->fb) < 0) + goto error; + if (xenfb_wait_for_frontend_initialised(&xenfb->kbd) < 0) + goto error; + + if (xenfb_bind(&xenfb->fb) < 0) + goto error; + if (xenfb_bind(&xenfb->kbd) < 0) + goto error; + + if (xenfb_xs_scanf1(xsh, xenfb->fb.otherend, "feature-update", + "%d", &val) < 0) + val = 0; + if (!val) { + errno = ENOTSUP; + goto error; + } + if (xenfb_xs_scanf1(xsh, xenfb->fb.otherend, "protocol", "%63s", + xenfb->protocol) < 0) + xenfb->protocol[0] = ''\0''; + xenfb_xs_printf(xsh, xenfb->fb.nodename, "request-update", "1"); + + /* TODO check for permitted ranges */ + fb_page = xenfb->fb.page; + xenfb->pub.depth = fb_page->depth; + xenfb->pub.width = fb_page->width; + xenfb->pub.height = fb_page->height; + /* TODO check for consistency with the above */ + xenfb->fb_len = fb_page->mem_length; + xenfb->pub.row_stride = fb_page->line_length; + + if (xenfb_map_fb(xenfb, domid) < 0) + goto error; + + if (xenfb_switch_state(&xenfb->fb, XenbusStateConnected)) + goto error; + if (xenfb_switch_state(&xenfb->kbd, XenbusStateConnected)) + goto error; + + if (xenfb_wait_for_frontend_connected(&xenfb->kbd) < 0) + goto error; + if (xenfb_xs_scanf1(xsh, xenfb->kbd.otherend, "request-abs-pointer", + "%d", &val) < 0) + val = 0; + xenfb->pub.abs_pointer_wanted = val; + + /* Listen for events from xenstore */ + if (qemu_set_fd_handler2(xs_fileno(xenfb->xsh), NULL, xenfb_dispatch_store, NULL, xenfb) < 0) + goto error; + + /* Listen for events from the event channel */ + if (qemu_set_fd_handler2(xc_evtchn_fd(xenfb->evt_xch), NULL, xenfb_dispatch_channel, NULL, xenfb) < 0) + goto error; + + return 0; + + error: + serrno = errno; + xenfb_detach_dom(xenfb); + xenfb_dev_fatal(&xenfb->fb, serrno, "on fire"); + xenfb_dev_fatal(&xenfb->kbd, serrno, "on fire"); + errno = serrno; + return -1; } static int xenfb_kbd_event(struct xenfb_private *xenfb, diff -r bd1bddd42929 tools/ioemu/hw/xenfb.h --- a/tools/ioemu/hw/xenfb.h Tue Aug 14 14:38:28 2007 -0400 +++ b/tools/ioemu/hw/xenfb.h Tue Aug 14 15:03:42 2007 -0400 @@ -25,13 +25,6 @@ void xenfb_teardown(struct xenfb *xenfb) int xenfb_attach_dom(struct xenfb *xenfb, int domid); -int xenfb_dispatch_store(struct xenfb *xenfb_pub); -int xenfb_dispatch_channel(struct xenfb *xenfb_pub); -int xenfb_select_fds(struct xenfb *xenfb, fd_set *readfds); -int xenfb_poll(struct xenfb *xenfb, fd_set *readfds); -int xenfb_get_store_fd(struct xenfb *xenfb_pub); -int xenfb_get_channel_fd(struct xenfb *xenfb_pub); - int xenfb_send_key(struct xenfb *xenfb, bool down, int keycode); int xenfb_send_motion(struct xenfb *xenfb, int rel_x, int rel_y); int xenfb_send_position(struct xenfb *xenfb, int abs_x, int abs_y); -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=| _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel P. Berrange
2007-Aug-15 20:07 UTC
Re: [Xen-devel] PATCH: 5/10: Refactor QEMU console integration
This patch moves a bunch of code out of the xen_machine_pv.c file and into the xenfb.c file. This is simply a re-factoring to facilitate the two patches which follow. xen_machine_pv.c | 132 ---------------------------- xenfb.c | 254 +++++++++++++++++++++++++++++++++++++++++-------------- xenfb.h | 8 - 3 files changed, 195 insertions(+), 199 deletions(-) Signed-off-by: Daniel P. Berrange <berrange@redhat.com> Dan. diff -r ff7bf037fe82 tools/ioemu/hw/xen_machine_pv.c --- a/tools/ioemu/hw/xen_machine_pv.c Tue Aug 14 15:13:39 2007 -0400 +++ b/tools/ioemu/hw/xen_machine_pv.c Tue Aug 14 15:25:29 2007 -0400 @@ -24,117 +24,6 @@ #include "vl.h" #include "xenfb.h" -#include <linux/input.h> - -/* A convenient function for munging pixels between different depths */ -#define BLT(SRC_T,DST_T,RLS,GLS,BLS,RRS,GRS,BRS,RM,GM,BM) \ - for (line = y ; line < h ; line++) { \ - SRC_T *src = (SRC_T *)(xenfb->pixels + (line*xenfb->row_stride) + (x*xenfb->depth/8)); \ - DST_T *dst = (DST_T *)(ds->data + (line*ds->linesize) + (x*ds->depth/8)); \ - int col; \ - for (col = x ; col < w ; col++) { \ - *dst = (((*src >> RRS)&RM) << RLS) | \ - (((*src >> GRS)&GM) << GLS) | \ - (((*src >> GRS)&BM) << BLS); \ - src++; \ - dst++; \ - } \ - } - - -/* This copies data from the guest framebuffer region, into QEMU''s copy - * NB. QEMU''s copy is stored in the pixel format of a) the local X server (SDL case) - * or b) the current VNC client pixel format. - */ -static void xen_pvfb_guest_copy(struct xenfb *xenfb, int x, int y, int w, int h) -{ - DisplayState *ds = (DisplayState *)xenfb->user_data; - int line; - - if (xenfb->depth == ds->depth) { /* Perfect match can use fast path */ - for (line = y ; line < (y+h) ; line++) { - memcpy(ds->data + (line * ds->linesize) + (x*ds->depth/8), - xenfb->pixels + (line*xenfb->row_stride) + (x*xenfb->depth/8), - w * xenfb->depth/8); - } - } else { /* Mismatch requires slow pixel munging */ - if (xenfb->depth == 8) { - /* 8 bit source == r:3 g:3 b:2 */ - if (ds->depth == 16) { - BLT(uint8_t, uint16_t, 5, 2, 0, 11, 5, 0, 7, 7, 3); - } else if (ds->depth == 32) { - BLT(uint8_t, uint32_t, 5, 2, 0, 16, 8, 0, 7, 7, 3); - } - } else if (xenfb->depth == 16) { - /* 16 bit source == r:5 g:6 b:5 */ - if (ds->depth == 8) { - BLT(uint16_t, uint8_t, 11, 5, 0, 5, 2, 0, 31, 63, 31); - } else if (ds->depth == 32) { - BLT(uint16_t, uint32_t, 11, 5, 0, 16, 8, 0, 31, 63, 31); - } - } else if (xenfb->depth == 32) { - /* 32 bit source == r:8 g:8 b:8 (padding:8) */ - if (ds->depth == 8) { - BLT(uint32_t, uint8_t, 16, 8, 0, 5, 2, 0, 255, 255, 255); - } else if (ds->depth == 16) { - BLT(uint32_t, uint16_t, 16, 8, 0, 11, 5, 0, 255, 255, 255); - } - } - } - dpy_update(ds, x, y, w, h); -} - - -/* Send a keypress from the client to the guest OS */ -static void xen_pvfb_put_keycode(void *opaque, int keycode) -{ - struct xenfb *xenfb = (struct xenfb*)opaque; - xenfb_send_key(xenfb, keycode & 0x80 ? 0 : 1, keycode & 0x7f); -} - -/* Send a mouse event from the client to the guest OS */ -static void xen_pvfb_mouse_event(void *opaque, - int dx, int dy, int dz, int button_state) -{ - static int old_state = 0; - int i; - struct xenfb *xenfb = (struct xenfb*)opaque; - DisplayState *ds = (DisplayState *)xenfb->user_data; - if (xenfb->abs_pointer_wanted) - xenfb_send_position(xenfb, - dx*ds->width/0x7fff, - dy*ds->height/0x7fff); - else - xenfb_send_motion(xenfb, dx, dy); - - for (i = 0 ; i < 8 ; i++) { - int lastDown = old_state & (1 << i); - int down = button_state & (1 << i); - if (down == lastDown) - continue; - - if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0) - return; - } - old_state = button_state; -} - -/* QEMU display state changed, so refresh the framebuffer copy */ -void xen_pvfb_update(void *opaque) -{ - struct xenfb *xenfb = (struct xenfb *)opaque; - xen_pvfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height); -} - -/* QEMU display state changed, so refresh the framebuffer copy */ -void xen_pvfb_invalidate(void *opaque) -{ - struct xenfb *xenfb = (struct xenfb *)opaque; - xen_pvfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height); -} - -/* Screen dump is not used in Xen, so no need to impl this ? */ -void xen_pvfb_screen_dump(void *opaque, const char *name) { } /* The Xen PV machine currently provides @@ -160,30 +49,11 @@ static void xen_init_pv(uint64_t ram_siz } /* Talk to the guest */ - if (xenfb_attach_dom(xenfb, domid) < 0) { + if (xenfb_attach_dom(xenfb, domid, ds) < 0) { fprintf(stderr, "Could not connect to domain (%s)\n", strerror(errno)); exit(1); } - xenfb->update = xen_pvfb_guest_copy; - xenfb->user_data = ds; - - /* Tell QEMU to allocate a graphical console */ - graphic_console_init(ds, - xen_pvfb_update, - xen_pvfb_invalidate, - xen_pvfb_screen_dump, - xenfb); - - /* Register our keyboard & mouse handlers */ - qemu_add_kbd_event_handler(xen_pvfb_put_keycode, xenfb); - qemu_add_mouse_event_handler(xen_pvfb_mouse_event, xenfb, - xenfb->abs_pointer_wanted, - "Xen PVFB Mouse"); - - - /* Setup QEMU display */ - dpy_resize(ds, xenfb->width, xenfb->height); } QEMUMachine xenpv_machine = { diff -r ff7bf037fe82 tools/ioemu/hw/xenfb.c --- a/tools/ioemu/hw/xenfb.c Tue Aug 14 15:13:39 2007 -0400 +++ b/tools/ioemu/hw/xenfb.c Tue Aug 14 15:25:52 2007 -0400 @@ -16,8 +16,8 @@ #include <string.h> #include <time.h> #include <xs.h> - -#include "vl.h" +#include <linux/input.h> + #include "xenfb.h" // FIXME defend against malicious frontend? @@ -586,6 +586,177 @@ static int xenfb_on_state_change(struct return 0; } +static int xenfb_kbd_event(struct xenfb_private *xenfb, + union xenkbd_in_event *event) +{ + uint32_t prod; + struct xenkbd_page *page = xenfb->kbd.page; + + if (xenfb->kbd.state != XenbusStateConnected) + return 0; + + prod = page->in_prod; + if (prod - page->in_cons == XENKBD_IN_RING_LEN) { + errno = EAGAIN; + return -1; + } + + mb(); /* ensure ring space available */ + XENKBD_IN_RING_REF(page, prod) = *event; + wmb(); /* ensure ring contents visible */ + page->in_prod = prod + 1; + return xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port); +} + +static int xenfb_send_key(struct xenfb *xenfb_pub, bool down, int keycode) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + union xenkbd_in_event event; + + memset(&event, 0, XENKBD_IN_EVENT_SIZE); + event.type = XENKBD_TYPE_KEY; + event.key.pressed = down ? 1 : 0; + event.key.keycode = keycode; + + return xenfb_kbd_event(xenfb, &event); +} + +static int xenfb_send_motion(struct xenfb *xenfb_pub, int rel_x, int rel_y) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + union xenkbd_in_event event; + + memset(&event, 0, XENKBD_IN_EVENT_SIZE); + event.type = XENKBD_TYPE_MOTION; + event.motion.rel_x = rel_x; + event.motion.rel_y = rel_y; + + return xenfb_kbd_event(xenfb, &event); +} + +static int xenfb_send_position(struct xenfb *xenfb_pub, int abs_x, int abs_y) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + union xenkbd_in_event event; + + memset(&event, 0, XENKBD_IN_EVENT_SIZE); + event.type = XENKBD_TYPE_POS; + event.pos.abs_x = abs_x; + event.pos.abs_y = abs_y; + + return xenfb_kbd_event(xenfb, &event); +} + +/* Send a keypress from the client to the guest OS */ +static void xenfb_put_keycode(void *opaque, int keycode) +{ + struct xenfb *xenfb = (struct xenfb*)opaque; + xenfb_send_key(xenfb, keycode & 0x80 ? 0 : 1, keycode & 0x7f); +} + +/* Send a mouse event from the client to the guest OS */ +static void xenfb_mouse_event(void *opaque, + int dx, int dy, int dz, int button_state) +{ + int i; + struct xenfb *xenfb = (struct xenfb*)opaque; + DisplayState *ds = (DisplayState *)xenfb->user_data; + if (xenfb->abs_pointer_wanted) + xenfb_send_position(xenfb, + dx*ds->width/0x7fff, + dy*ds->height/0x7fff); + else + xenfb_send_motion(xenfb, dx, dy); + + for (i = 0 ; i < 8 ; i++) { + int lastDown = xenfb->button_state & (1 << i); + int down = button_state & (1 << i); + if (down == lastDown) + continue; + + if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0) + return; + } + xenfb->button_state = button_state; +} + +/* A convenient function for munging pixels between different depths */ +#define BLT(SRC_T,DST_T,RLS,GLS,BLS,RRS,GRS,BRS,RM,GM,BM) \ + for (line = y ; line < h ; line++) { \ + SRC_T *src = (SRC_T *)(xenfb->pixels + (line*xenfb->row_stride) + (x*xenfb->depth/8)); \ + DST_T *dst = (DST_T *)(ds->data + (line*ds->linesize) + (x*ds->depth/8)); \ + int col; \ + for (col = x ; col < w ; col++) { \ + *dst = (((*src >> RRS)&RM) << RLS) | \ + (((*src >> GRS)&GM) << GLS) | \ + (((*src >> GRS)&BM) << BLS); \ + src++; \ + dst++; \ + } \ + } + + +/* This copies data from the guest framebuffer region, into QEMU''s copy + * NB. QEMU''s copy is stored in the pixel format of a) the local X server (SDL case) + * or b) the current VNC client pixel format. + */ +static void xenfb_guest_copy(struct xenfb *xenfb, int x, int y, int w, int h) +{ + DisplayState *ds = (DisplayState *)xenfb->user_data; + int line; + + if (xenfb->depth == ds->depth) { /* Perfect match can use fast path */ + for (line = y ; line < (y+h) ; line++) { + memcpy(ds->data + (line * ds->linesize) + (x*ds->depth/8), + xenfb->pixels + (line*xenfb->row_stride) + (x*xenfb->depth/8), + w * xenfb->depth/8); + } + } else { /* Mismatch requires slow pixel munging */ + if (xenfb->depth == 8) { + /* 8 bit source == r:3 g:3 b:2 */ + if (ds->depth == 16) { + BLT(uint8_t, uint16_t, 5, 2, 0, 11, 5, 0, 7, 7, 3); + } else if (ds->depth == 32) { + BLT(uint8_t, uint32_t, 5, 2, 0, 16, 8, 0, 7, 7, 3); + } + } else if (xenfb->depth == 16) { + /* 16 bit source == r:5 g:6 b:5 */ + if (ds->depth == 8) { + BLT(uint16_t, uint8_t, 11, 5, 0, 5, 2, 0, 31, 63, 31); + } else if (ds->depth == 32) { + BLT(uint16_t, uint32_t, 11, 5, 0, 16, 8, 0, 31, 63, 31); + } + } else if (xenfb->depth == 32) { + /* 32 bit source == r:8 g:8 b:8 (padding:8) */ + if (ds->depth == 8) { + BLT(uint32_t, uint8_t, 16, 8, 0, 5, 2, 0, 255, 255, 255); + } else if (ds->depth == 16) { + BLT(uint32_t, uint16_t, 16, 8, 0, 11, 5, 0, 255, 255, 255); + } + } + } + dpy_update(ds, x, y, w, h); +} + +/* QEMU display state changed, so refresh the framebuffer copy */ +static void xenfb_update(void *opaque) +{ + struct xenfb *xenfb = (struct xenfb *)opaque; + xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height); +} + +/* QEMU display state changed, so refresh the framebuffer copy */ +static void xenfb_invalidate(void *opaque) +{ + struct xenfb *xenfb = (struct xenfb *)opaque; + xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height); +} + +/* Screen dump is not used in Xen, so no need to impl this ? */ +static void xenfb_screen_dump(void *opaque, const char *name) { } + + + static void xenfb_dispatch_channel(void *xenfb_pub) { struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; @@ -620,7 +791,7 @@ static void xenfb_dispatch_store(void *x } -int xenfb_attach_dom(struct xenfb *xenfb_pub, int domid) +int xenfb_attach_dom(struct xenfb *xenfb_pub, int domid, DisplayState *ds) { struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; struct xs_handle *xsh = xenfb->xsh; @@ -708,6 +879,23 @@ int xenfb_attach_dom(struct xenfb *xenfb if (qemu_set_fd_handler2(xc_evtchn_fd(xenfb->evt_xch), NULL, xenfb_dispatch_channel, NULL, xenfb) < 0) goto error; + /* Register our keyboard & mouse handlers */ + qemu_add_kbd_event_handler(xenfb_put_keycode, xenfb); + qemu_add_mouse_event_handler(xenfb_mouse_event, xenfb, + xenfb_pub->abs_pointer_wanted, + "Xen PVFB Mouse"); + + xenfb_pub->update = xenfb_guest_copy; + xenfb_pub->user_data = ds; + + /* Tell QEMU to allocate a graphical console */ + graphic_console_init(ds, + xenfb_update, + xenfb_invalidate, + xenfb_screen_dump, + xenfb_pub); + dpy_resize(ds, xenfb_pub->width, xenfb_pub->height); + return 0; error: @@ -719,66 +907,6 @@ int xenfb_attach_dom(struct xenfb *xenfb return -1; } -static int xenfb_kbd_event(struct xenfb_private *xenfb, - union xenkbd_in_event *event) -{ - uint32_t prod; - struct xenkbd_page *page = xenfb->kbd.page; - - if (xenfb->kbd.state != XenbusStateConnected) - return 0; - - prod = page->in_prod; - if (prod - page->in_cons == XENKBD_IN_RING_LEN) { - errno = EAGAIN; - return -1; - } - - mb(); /* ensure ring space available */ - XENKBD_IN_RING_REF(page, prod) = *event; - wmb(); /* ensure ring contents visible */ - page->in_prod = prod + 1; - return xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port); -} - -int xenfb_send_key(struct xenfb *xenfb_pub, bool down, int keycode) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - union xenkbd_in_event event; - - memset(&event, 0, XENKBD_IN_EVENT_SIZE); - event.type = XENKBD_TYPE_KEY; - event.key.pressed = down ? 1 : 0; - event.key.keycode = keycode; - - return xenfb_kbd_event(xenfb, &event); -} - -int xenfb_send_motion(struct xenfb *xenfb_pub, int rel_x, int rel_y) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - union xenkbd_in_event event; - - memset(&event, 0, XENKBD_IN_EVENT_SIZE); - event.type = XENKBD_TYPE_MOTION; - event.motion.rel_x = rel_x; - event.motion.rel_y = rel_y; - - return xenfb_kbd_event(xenfb, &event); -} - -int xenfb_send_position(struct xenfb *xenfb_pub, int abs_x, int abs_y) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - union xenkbd_in_event event; - - memset(&event, 0, XENKBD_IN_EVENT_SIZE); - event.type = XENKBD_TYPE_POS; - event.pos.abs_x = abs_x; - event.pos.abs_y = abs_y; - - return xenfb_kbd_event(xenfb, &event); -} /* * Local variables: * c-indent-level: 8 diff -r ff7bf037fe82 tools/ioemu/hw/xenfb.h --- a/tools/ioemu/hw/xenfb.h Tue Aug 14 15:13:39 2007 -0400 +++ b/tools/ioemu/hw/xenfb.h Tue Aug 14 15:22:15 2007 -0400 @@ -1,6 +1,7 @@ #ifndef _XENFB_H_ #define _XENFB_H_ +#include "vl.h" #include <stdbool.h> #include <sys/types.h> @@ -13,6 +14,7 @@ struct xenfb int width; int height; int abs_pointer_wanted; + int button_state; void *user_data; @@ -23,10 +25,6 @@ void xenfb_delete(struct xenfb *xenfb); void xenfb_delete(struct xenfb *xenfb); void xenfb_teardown(struct xenfb *xenfb); -int xenfb_attach_dom(struct xenfb *xenfb, int domid); - -int xenfb_send_key(struct xenfb *xenfb, bool down, int keycode); -int xenfb_send_motion(struct xenfb *xenfb, int rel_x, int rel_y); -int xenfb_send_position(struct xenfb *xenfb, int abs_x, int abs_y); +int xenfb_attach_dom(struct xenfb *xenfb, int domid, DisplayState *ds); #endif -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=| _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel P. Berrange
2007-Aug-15 20:08 UTC
Re: [Xen-devel] PATCH: 6/10: Merge private & public xenfb structs
This patch merges the public & private structs from the paravirt FB into a single struct. Since QEMU is the only consumer of this code there is no need for the artifical pub/priv split. Merging the two will make it possible to more tightly integrate with QEMU''s event loop and do asynchronous non-blocking negoiation with the frontend devices (see next patch). xenfb.c | 273 ++++++++++++++++++++++++++++++++-------------------------------- xenfb.h | 16 --- 2 files changed, 139 insertions(+), 150 deletions(-) Signed-off-by: Daniel P. Berrange <berrange@redhat.com> Dan. diff -r 82c317f263c2 tools/ioemu/hw/xenfb.c --- a/tools/ioemu/hw/xenfb.c Tue Aug 14 15:26:57 2007 -0400 +++ b/tools/ioemu/hw/xenfb.c Tue Aug 14 15:45:22 2007 -0400 @@ -22,6 +22,8 @@ // FIXME defend against malicious frontend? +struct xenfb; + struct xenfb_device { const char *devicetype; char nodename[64]; /* backend xenstore dir */ @@ -30,20 +32,33 @@ struct xenfb_device { enum xenbus_state state; /* backend state */ void *page; /* shared page */ evtchn_port_t port; - struct xenfb_private *xenfb; + struct xenfb *xenfb; }; -struct xenfb_private { - struct xenfb pub; +struct xenfb_data +{ + void *pixels; + size_t len; + + int row_stride; + int depth; + int width; + int height; + int abs_pointer_wanted; +}; + +struct xenfb { + DisplayState *ds; int evt_xch; /* event channel driver handle */ int xc; /* hypervisor interface handle */ struct xs_handle *xsh; /* xs daemon handle */ struct xenfb_device fb, kbd; - size_t fb_len; /* size of framebuffer */ + struct xenfb_data data; char protocol[64]; /* frontend protocol */ + int button_state; }; -static void xenfb_detach_dom(struct xenfb_private *); +static void xenfb_detach_dom(struct xenfb *); static char *xenfb_path_in_dom(struct xs_handle *xsh, char *buf, size_t size, @@ -124,7 +139,7 @@ static int xenfb_xs_printf(struct xs_han static void xenfb_device_init(struct xenfb_device *dev, const char *type, - struct xenfb_private *xenfb) + struct xenfb *xenfb) { dev->devicetype = type; dev->otherend_id = -1; @@ -132,19 +147,17 @@ static void xenfb_device_init(struct xen dev->xenfb = xenfb; } -int xenfb_device_set_domain(struct xenfb_device *dev, int domid) -{ - struct xenfb_private *xenfb = dev->xenfb; - +static int xenfb_device_set_domain(struct xenfb_device *dev, int domid) +{ dev->otherend_id = domid; - if (!xenfb_path_in_dom(xenfb->xsh, + if (!xenfb_path_in_dom(dev->xenfb->xsh, dev->otherend, sizeof(dev->otherend), domid, "device/%s/0", dev->devicetype)) { errno = ENOENT; return -1; } - if (!xenfb_path_in_dom(xenfb->xsh, + if (!xenfb_path_in_dom(dev->xenfb->xsh, dev->nodename, sizeof(dev->nodename), 0, "backend/%s/%d/0", dev->devicetype, domid)) { errno = ENOENT; @@ -156,8 +169,8 @@ int xenfb_device_set_domain(struct xenfb struct xenfb *xenfb_new(void) { - struct xenfb_private *xenfb = malloc(sizeof(*xenfb)); int serrno; + struct xenfb *xenfb = qemu_malloc(sizeof(struct xenfb)); if (xenfb == NULL) return NULL; @@ -179,30 +192,26 @@ struct xenfb *xenfb_new(void) if (!xenfb->xsh) goto fail; - return &xenfb->pub; + return xenfb; fail: serrno = errno; - xenfb_delete(&xenfb->pub); + xenfb_delete(xenfb); errno = serrno; return NULL; } /* Remove the backend area in xenbus since the framebuffer really is going away. */ -void xenfb_teardown(struct xenfb *xenfb_pub) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - +void xenfb_teardown(struct xenfb *xenfb) +{ xs_rm(xenfb->xsh, XBT_NULL, xenfb->fb.nodename); xs_rm(xenfb->xsh, XBT_NULL, xenfb->kbd.nodename); } -void xenfb_delete(struct xenfb *xenfb_pub) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - +void xenfb_delete(struct xenfb *xenfb) +{ xenfb_detach_dom(xenfb); if (xenfb->xc >= 0) xc_interface_close(xenfb->xc); @@ -334,7 +343,7 @@ static void xenfb_copy_mfns(int mode, in dst[i] = (mode == 32) ? src32[i] : src64[i]; } -static int xenfb_map_fb(struct xenfb_private *xenfb, int domid) +static int xenfb_map_fb(struct xenfb *xenfb, int domid) { struct xenfb_page *page = xenfb->fb.page; int n_fbmfns; @@ -389,7 +398,7 @@ static int xenfb_map_fb(struct xenfb_pri #endif } - n_fbmfns = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE; + n_fbmfns = (xenfb->data.len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE; n_fbdirs = n_fbmfns * mode / 8; n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE; @@ -412,9 +421,9 @@ static int xenfb_map_fb(struct xenfb_pri xenfb_copy_mfns(mode, n_fbmfns, fbmfns, map); munmap(map, n_fbdirs * XC_PAGE_SIZE); - xenfb->pub.pixels = xc_map_foreign_batch(xenfb->xc, domid, + xenfb->data.pixels = xc_map_foreign_batch(xenfb->xc, domid, PROT_READ | PROT_WRITE, fbmfns, n_fbmfns); - if (xenfb->pub.pixels == NULL) + if (xenfb->data.pixels == NULL) goto out; ret = 0; /* all is fine */ @@ -429,7 +438,7 @@ static int xenfb_map_fb(struct xenfb_pri static int xenfb_bind(struct xenfb_device *dev) { - struct xenfb_private *xenfb = dev->xenfb; + struct xenfb *xenfb = dev->xenfb; unsigned long mfn; evtchn_port_t evtchn; @@ -512,17 +521,74 @@ static void xenfb_dev_fatal(struct xenfb } -static void xenfb_detach_dom(struct xenfb_private *xenfb) +static void xenfb_detach_dom(struct xenfb *xenfb) { xenfb_unbind(&xenfb->fb); xenfb_unbind(&xenfb->kbd); - if (xenfb->pub.pixels) { - munmap(xenfb->pub.pixels, xenfb->fb_len); - xenfb->pub.pixels = NULL; - } -} - -static void xenfb_on_fb_event(struct xenfb_private *xenfb) + if (xenfb->data.pixels) { + munmap(xenfb->data.pixels, xenfb->data.len); + xenfb->data.pixels = NULL; + } +} + +/* A convenient function for munging pixels between different depths */ +#define BLT(SRC_T,DST_T,RLS,GLS,BLS,RRS,GRS,BRS,RM,GM,BM) \ + for (line = y ; line < h ; line++) { \ + SRC_T *src = (SRC_T *)(xenfb->data.pixels + (line*xenfb->data.row_stride) + (x*xenfb->data.depth/8)); \ + DST_T *dst = (DST_T *)(xenfb->ds->data + (line*xenfb->ds->linesize) + (x*xenfb->ds->depth/8)); \ + int col; \ + for (col = x ; col < w ; col++) { \ + *dst = (((*src >> RRS)&RM) << RLS) | \ + (((*src >> GRS)&GM) << GLS) | \ + (((*src >> GRS)&BM) << BLS); \ + src++; \ + dst++; \ + } \ + } + + +/* This copies data from the guest framebuffer region, into QEMU''s copy + * NB. QEMU''s copy is stored in the pixel format of a) the local X server (SDL case) + * or b) the current VNC client pixel format. + */ +static void xenfb_guest_copy(struct xenfb *xenfb, int x, int y, int w, int h) +{ + int line; + + if (xenfb->data.depth == xenfb->ds->depth) { /* Perfect match can use fast path */ + for (line = y ; line < (y+h) ; line++) { + memcpy(xenfb->ds->data + (line * xenfb->ds->linesize) + (x*xenfb->ds->depth/8), + xenfb->data.pixels + (line*xenfb->data.row_stride) + (x*xenfb->data.depth/8), + w * xenfb->data.depth/8); + } + } else { /* Mismatch requires slow pixel munging */ + if (xenfb->data.depth == 8) { + /* 8 bit source == r:3 g:3 b:2 */ + if (xenfb->ds->depth == 16) { + BLT(uint8_t, uint16_t, 5, 2, 0, 11, 5, 0, 7, 7, 3); + } else if (xenfb->ds->depth == 32) { + BLT(uint8_t, uint32_t, 5, 2, 0, 16, 8, 0, 7, 7, 3); + } + } else if (xenfb->data.depth == 16) { + /* 16 bit source == r:5 g:6 b:5 */ + if (xenfb->ds->depth == 8) { + BLT(uint16_t, uint8_t, 11, 5, 0, 5, 2, 0, 31, 63, 31); + } else if (xenfb->ds->depth == 32) { + BLT(uint16_t, uint32_t, 11, 5, 0, 16, 8, 0, 31, 63, 31); + } + } else if (xenfb->data.depth == 32) { + /* 32 bit source == r:8 g:8 b:8 (padding:8) */ + if (xenfb->ds->depth == 8) { + BLT(uint32_t, uint8_t, 16, 8, 0, 5, 2, 0, 255, 255, 255); + } else if (xenfb->ds->depth == 16) { + BLT(uint32_t, uint16_t, 16, 8, 0, 11, 5, 0, 255, 255, 255); + } + } + } + dpy_update(xenfb->ds, x, y, w, h); +} + +static void xenfb_on_fb_event(struct xenfb *xenfb) { uint32_t prod, cons; struct xenfb_page *page = xenfb->fb.page; @@ -536,11 +602,10 @@ static void xenfb_on_fb_event(struct xen switch (event->type) { case XENFB_TYPE_UPDATE: - if (xenfb->pub.update) - xenfb->pub.update(&xenfb->pub, - event->update.x, event->update.y, - event->update.width, event->update.height); - break; + xenfb_guest_copy(xenfb, + event->update.x, event->update.y, + event->update.width, event->update.height); + break; } } mb(); /* ensure we''re done with ring contents */ @@ -548,7 +613,7 @@ static void xenfb_on_fb_event(struct xen xc_evtchn_notify(xenfb->evt_xch, xenfb->fb.port); } -static void xenfb_on_kbd_event(struct xenfb_private *xenfb) +static void xenfb_on_kbd_event(struct xenfb *xenfb) { struct xenkbd_page *page = xenfb->kbd.page; @@ -586,7 +651,7 @@ static int xenfb_on_state_change(struct return 0; } -static int xenfb_kbd_event(struct xenfb_private *xenfb, +static int xenfb_kbd_event(struct xenfb *xenfb, union xenkbd_in_event *event) { uint32_t prod; @@ -608,9 +673,8 @@ static int xenfb_kbd_event(struct xenfb_ return xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port); } -static int xenfb_send_key(struct xenfb *xenfb_pub, bool down, int keycode) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; +static int xenfb_send_key(struct xenfb *xenfb, bool down, int keycode) +{ union xenkbd_in_event event; memset(&event, 0, XENKBD_IN_EVENT_SIZE); @@ -621,9 +685,8 @@ static int xenfb_send_key(struct xenfb * return xenfb_kbd_event(xenfb, &event); } -static int xenfb_send_motion(struct xenfb *xenfb_pub, int rel_x, int rel_y) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; +static int xenfb_send_motion(struct xenfb *xenfb, int rel_x, int rel_y) +{ union xenkbd_in_event event; memset(&event, 0, XENKBD_IN_EVENT_SIZE); @@ -634,9 +697,8 @@ static int xenfb_send_motion(struct xenf return xenfb_kbd_event(xenfb, &event); } -static int xenfb_send_position(struct xenfb *xenfb_pub, int abs_x, int abs_y) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; +static int xenfb_send_position(struct xenfb *xenfb, int abs_x, int abs_y) +{ union xenkbd_in_event event; memset(&event, 0, XENKBD_IN_EVENT_SIZE); @@ -660,11 +722,11 @@ static void xenfb_mouse_event(void *opaq { int i; struct xenfb *xenfb = (struct xenfb*)opaque; - DisplayState *ds = (DisplayState *)xenfb->user_data; - if (xenfb->abs_pointer_wanted) + + if (xenfb->data.abs_pointer_wanted) xenfb_send_position(xenfb, - dx*ds->width/0x7fff, - dy*ds->height/0x7fff); + dx*xenfb->ds->width/0x7fff, + dy*xenfb->ds->height/0x7fff); else xenfb_send_motion(xenfb, dx, dy); @@ -680,76 +742,19 @@ static void xenfb_mouse_event(void *opaq xenfb->button_state = button_state; } -/* A convenient function for munging pixels between different depths */ -#define BLT(SRC_T,DST_T,RLS,GLS,BLS,RRS,GRS,BRS,RM,GM,BM) \ - for (line = y ; line < h ; line++) { \ - SRC_T *src = (SRC_T *)(xenfb->pixels + (line*xenfb->row_stride) + (x*xenfb->depth/8)); \ - DST_T *dst = (DST_T *)(ds->data + (line*ds->linesize) + (x*ds->depth/8)); \ - int col; \ - for (col = x ; col < w ; col++) { \ - *dst = (((*src >> RRS)&RM) << RLS) | \ - (((*src >> GRS)&GM) << GLS) | \ - (((*src >> GRS)&BM) << BLS); \ - src++; \ - dst++; \ - } \ - } - - -/* This copies data from the guest framebuffer region, into QEMU''s copy - * NB. QEMU''s copy is stored in the pixel format of a) the local X server (SDL case) - * or b) the current VNC client pixel format. - */ -static void xenfb_guest_copy(struct xenfb *xenfb, int x, int y, int w, int h) -{ - DisplayState *ds = (DisplayState *)xenfb->user_data; - int line; - - if (xenfb->depth == ds->depth) { /* Perfect match can use fast path */ - for (line = y ; line < (y+h) ; line++) { - memcpy(ds->data + (line * ds->linesize) + (x*ds->depth/8), - xenfb->pixels + (line*xenfb->row_stride) + (x*xenfb->depth/8), - w * xenfb->depth/8); - } - } else { /* Mismatch requires slow pixel munging */ - if (xenfb->depth == 8) { - /* 8 bit source == r:3 g:3 b:2 */ - if (ds->depth == 16) { - BLT(uint8_t, uint16_t, 5, 2, 0, 11, 5, 0, 7, 7, 3); - } else if (ds->depth == 32) { - BLT(uint8_t, uint32_t, 5, 2, 0, 16, 8, 0, 7, 7, 3); - } - } else if (xenfb->depth == 16) { - /* 16 bit source == r:5 g:6 b:5 */ - if (ds->depth == 8) { - BLT(uint16_t, uint8_t, 11, 5, 0, 5, 2, 0, 31, 63, 31); - } else if (ds->depth == 32) { - BLT(uint16_t, uint32_t, 11, 5, 0, 16, 8, 0, 31, 63, 31); - } - } else if (xenfb->depth == 32) { - /* 32 bit source == r:8 g:8 b:8 (padding:8) */ - if (ds->depth == 8) { - BLT(uint32_t, uint8_t, 16, 8, 0, 5, 2, 0, 255, 255, 255); - } else if (ds->depth == 16) { - BLT(uint32_t, uint16_t, 16, 8, 0, 11, 5, 0, 255, 255, 255); - } - } - } - dpy_update(ds, x, y, w, h); -} /* QEMU display state changed, so refresh the framebuffer copy */ static void xenfb_update(void *opaque) { struct xenfb *xenfb = (struct xenfb *)opaque; - xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height); + xenfb_guest_copy(xenfb, 0, 0, xenfb->data.width, xenfb->data.height); } /* QEMU display state changed, so refresh the framebuffer copy */ static void xenfb_invalidate(void *opaque) { struct xenfb *xenfb = (struct xenfb *)opaque; - xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height); + xenfb_guest_copy(xenfb, 0, 0, xenfb->data.width, xenfb->data.height); } /* Screen dump is not used in Xen, so no need to impl this ? */ @@ -757,9 +762,9 @@ static void xenfb_screen_dump(void *opaq -static void xenfb_dispatch_channel(void *xenfb_pub) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; +static void xenfb_dispatch_channel(void *opaque) +{ + struct xenfb *xenfb = (struct xenfb *)opaque; evtchn_port_t port; port = xc_evtchn_pending(xenfb->evt_xch); if (port == -1) @@ -774,9 +779,9 @@ static void xenfb_dispatch_channel(void exit(1); } -static void xenfb_dispatch_store(void *xenfb_pub) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; +static void xenfb_dispatch_store(void *opaque) +{ + struct xenfb *xenfb = (struct xenfb *)opaque; unsigned dummy; char **vec; int r; @@ -791,9 +796,8 @@ static void xenfb_dispatch_store(void *x } -int xenfb_attach_dom(struct xenfb *xenfb_pub, int domid, DisplayState *ds) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; +int xenfb_attach_dom(struct xenfb *xenfb, int domid, DisplayState *ds) +{ struct xs_handle *xsh = xenfb->xsh; int val, serrno; struct xenfb_page *fb_page; @@ -849,12 +853,12 @@ int xenfb_attach_dom(struct xenfb *xenfb /* TODO check for permitted ranges */ fb_page = xenfb->fb.page; - xenfb->pub.depth = fb_page->depth; - xenfb->pub.width = fb_page->width; - xenfb->pub.height = fb_page->height; + xenfb->data.depth = fb_page->depth; + xenfb->data.width = fb_page->width; + xenfb->data.height = fb_page->height; /* TODO check for consistency with the above */ - xenfb->fb_len = fb_page->mem_length; - xenfb->pub.row_stride = fb_page->line_length; + xenfb->data.len = fb_page->mem_length; + xenfb->data.row_stride = fb_page->line_length; if (xenfb_map_fb(xenfb, domid) < 0) goto error; @@ -869,7 +873,7 @@ int xenfb_attach_dom(struct xenfb *xenfb if (xenfb_xs_scanf1(xsh, xenfb->kbd.otherend, "request-abs-pointer", "%d", &val) < 0) val = 0; - xenfb->pub.abs_pointer_wanted = val; + xenfb->data.abs_pointer_wanted = val; /* Listen for events from xenstore */ if (qemu_set_fd_handler2(xs_fileno(xenfb->xsh), NULL, xenfb_dispatch_store, NULL, xenfb) < 0) @@ -882,19 +886,18 @@ int xenfb_attach_dom(struct xenfb *xenfb /* Register our keyboard & mouse handlers */ qemu_add_kbd_event_handler(xenfb_put_keycode, xenfb); qemu_add_mouse_event_handler(xenfb_mouse_event, xenfb, - xenfb_pub->abs_pointer_wanted, + xenfb->data.abs_pointer_wanted, "Xen PVFB Mouse"); - xenfb_pub->update = xenfb_guest_copy; - xenfb_pub->user_data = ds; + xenfb->ds = ds; /* Tell QEMU to allocate a graphical console */ graphic_console_init(ds, xenfb_update, xenfb_invalidate, xenfb_screen_dump, - xenfb_pub); - dpy_resize(ds, xenfb_pub->width, xenfb_pub->height); + xenfb); + dpy_resize(ds, xenfb->data.width, xenfb->data.height); return 0; diff -r 82c317f263c2 tools/ioemu/hw/xenfb.h --- a/tools/ioemu/hw/xenfb.h Tue Aug 14 15:26:57 2007 -0400 +++ b/tools/ioemu/hw/xenfb.h Tue Aug 14 15:32:58 2007 -0400 @@ -5,21 +5,7 @@ #include <stdbool.h> #include <sys/types.h> -struct xenfb -{ - void *pixels; - - int row_stride; - int depth; - int width; - int height; - int abs_pointer_wanted; - int button_state; - - void *user_data; - - void (*update)(struct xenfb *xenfb, int x, int y, int width, int height); -}; +struct xenfb; struct xenfb *xenfb_new(void); void xenfb_delete(struct xenfb *xenfb); -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=| _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel P. Berrange
2007-Aug-15 20:09 UTC
Re: [Xen-devel] PATCH: 7/10: Async negotiation with xenfb frontend
This patch re-factors the paravirt console xenfb_attach_dom method. The original method blocks the caller until the front & backends have both switched to the connected state. This isn''t an immediate problem, but patches which follow will extend qemu to also handle the text console so blocking on graphics console startup will block the text console processing. The new code is basically a state machine. It starts off with a watch waiting for the KBD backend to switch to ''initialized'' mode, then does the same for the FB backend. Now it waits for KBD & FB frontend devices to initialize, reading & mapping the framebuffer & its config at the appropriate step. When the KBD frontend finally reaches the connected state it registers a graphical console with QEMU and sets up the various framebuffer, mouse & keyboard event handlers. If a client connects to the VNC server before this is completed, then they will merely see a text console (or perhaps the monitor if configured that way). xen_machine_pv.c | 9 xenfb.c | 687 ++++++++++++++++++++++++++++++++----------------------- xenfb.h | 7 3 files changed, 405 insertions(+), 298 deletions(-) Signed-off-by: Daniel P. Berrange <berrange@redhat.com> Dan. diff -r 90a6b110dc00 tools/ioemu/hw/xen_machine_pv.c --- a/tools/ioemu/hw/xen_machine_pv.c Tue Aug 14 15:46:31 2007 -0400 +++ b/tools/ioemu/hw/xen_machine_pv.c Tue Aug 14 16:04:25 2007 -0400 @@ -41,16 +41,9 @@ static void xen_init_pv(uint64_t ram_siz extern int domid; /* Prepare PVFB state */ - xenfb = xenfb_new(); + xenfb = xenfb_new(domid, ds); if (xenfb == NULL) { fprintf(stderr, "Could not create framebuffer (%s)\n", - strerror(errno)); - exit(1); - } - - /* Talk to the guest */ - if (xenfb_attach_dom(xenfb, domid, ds) < 0) { - fprintf(stderr, "Could not connect to domain (%s)\n", strerror(errno)); exit(1); } diff -r 90a6b110dc00 tools/ioemu/hw/xenfb.c --- a/tools/ioemu/hw/xenfb.c Tue Aug 14 15:46:31 2007 -0400 +++ b/tools/ioemu/hw/xenfb.c Tue Aug 14 16:58:46 2007 -0400 @@ -167,60 +167,6 @@ static int xenfb_device_set_domain(struc return 0; } -struct xenfb *xenfb_new(void) -{ - int serrno; - struct xenfb *xenfb = qemu_malloc(sizeof(struct xenfb)); - - if (xenfb == NULL) - return NULL; - - memset(xenfb, 0, sizeof(*xenfb)); - xenfb->evt_xch = xenfb->xc = -1; - xenfb_device_init(&xenfb->fb, "vfb", xenfb); - xenfb_device_init(&xenfb->kbd, "vkbd", xenfb); - - xenfb->evt_xch = xc_evtchn_open(); - if (xenfb->evt_xch == -1) - goto fail; - - xenfb->xc = xc_interface_open(); - if (xenfb->xc == -1) - goto fail; - - xenfb->xsh = xs_daemon_open(); - if (!xenfb->xsh) - goto fail; - - return xenfb; - - fail: - serrno = errno; - xenfb_delete(xenfb); - errno = serrno; - return NULL; -} - -/* Remove the backend area in xenbus since the framebuffer really is - going away. */ -void xenfb_teardown(struct xenfb *xenfb) -{ - xs_rm(xenfb->xsh, XBT_NULL, xenfb->fb.nodename); - xs_rm(xenfb->xsh, XBT_NULL, xenfb->kbd.nodename); -} - - -void xenfb_delete(struct xenfb *xenfb) -{ - xenfb_detach_dom(xenfb); - if (xenfb->xc >= 0) - xc_interface_close(xenfb->xc); - if (xenfb->evt_xch >= 0) - xc_evtchn_close(xenfb->evt_xch); - if (xenfb->xsh) - xs_daemon_close(xenfb->xsh); - free(xenfb); -} static enum xenbus_state xenfb_read_state(struct xs_handle *xsh, const char *dir) @@ -247,61 +193,6 @@ 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, @@ -310,28 +201,6 @@ static int xenfb_hotplug(struct xenfb_de return 0; } -static int xenfb_wait_for_frontend_initialised(struct xenfb_device *dev) -{ - switch (xenfb_wait_for_state(dev->xenfb->xsh, dev->otherend, -#if 1 /* TODO fudging state to permit restarting; to be removed */ - (1 << XenbusStateInitialised) - | (1 << XenbusStateConnected) -#else - 1 << XenbusStateInitialised, -#endif - )) { -#if 1 - case XenbusStateConnected: - printf("Fudging state to %d\n", XenbusStateInitialised); /* FIXME */ -#endif - case XenbusStateInitialised: - break; - default: - return -1; - } - - return 0; -} static void xenfb_copy_mfns(int mode, int count, unsigned long *dst, void *src) { @@ -474,52 +343,6 @@ static void xenfb_unbind(struct xenfb_de } } -static int xenfb_wait_for_frontend_connected(struct xenfb_device *dev) -{ - switch (xenfb_wait_for_state(dev->xenfb->xsh, dev->otherend, - 1 << XenbusStateConnected)) { - case XenbusStateConnected: - break; - default: - return -1; - } - - return 0; -} - -static void xenfb_dev_fatal(struct xenfb_device *dev, int err, - const char *fmt, ...) -{ - struct xs_handle *xsh = dev->xenfb->xsh; - va_list ap; - char errdir[80]; - char buf[1024]; - int n; - - fprintf(stderr, "%s ", dev->nodename); /* somewhat crude */ - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - if (err) - fprintf(stderr, " (%s)", strerror(err)); - putc(''\n'', stderr); - - if (!xenfb_path_in_dom(xsh, errdir, sizeof(errdir), 0, - "error/%s", dev->nodename)) - goto out; /* FIXME complain */ - - va_start(ap, fmt); - n = snprintf(buf, sizeof(buf), "%d ", err); - snprintf(buf + n, sizeof(buf) - n, fmt, ap); - va_end(ap); - - if (xenfb_xs_printf(xsh, buf, "error", "%s", buf) < 0) - goto out; /* FIXME complain */ - - out: - xenfb_switch_state(dev, XenbusStateClosing); -} - static void xenfb_detach_dom(struct xenfb *xenfb) { @@ -673,6 +496,8 @@ static int xenfb_kbd_event(struct xenfb return xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port); } + +/* Send a keyboard (or mouse button) event */ static int xenfb_send_key(struct xenfb *xenfb, bool down, int keycode) { union xenkbd_in_event event; @@ -685,6 +510,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; @@ -697,6 +523,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; @@ -761,24 +588,30 @@ static void xenfb_screen_dump(void *opaq static void xenfb_screen_dump(void *opaque, const char *name) { } - +/* Process events from the frontend event channel */ static void xenfb_dispatch_channel(void *opaque) { struct xenfb *xenfb = (struct xenfb *)opaque; evtchn_port_t port; port = xc_evtchn_pending(xenfb->evt_xch); - if (port == -1) + if (port == -1) { + xenfb_shutdown(xenfb); exit(1); + } if (port == xenfb->fb.port) xenfb_on_fb_event(xenfb); else if (port == xenfb->kbd.port) xenfb_on_kbd_event(xenfb); - if (xc_evtchn_unmask(xenfb->evt_xch, port) == -1) + if (xc_evtchn_unmask(xenfb->evt_xch, port) == -1) { + xenfb_shutdown(xenfb); exit(1); -} - + } +} + + +/* Process ongoing events from the frontend devices */ static void xenfb_dispatch_store(void *opaque) { struct xenfb *xenfb = (struct xenfb *)opaque; @@ -791,123 +624,407 @@ 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; - struct xenfb_page *fb_page; - - xenfb_detach_dom(xenfb); - - xenfb_device_set_domain(&xenfb->fb, domid); - xenfb_device_set_domain(&xenfb->kbd, domid); - - if (xenfb_wait_for_backend_creation(&xenfb->fb) < 0) - goto error; - if (xenfb_wait_for_backend_creation(&xenfb->kbd) < 0) - goto error; - - if (xenfb_xs_printf(xsh, xenfb->kbd.nodename, "feature-abs-pointer", "1")) - goto error; - if (xenfb_switch_state(&xenfb->fb, XenbusStateInitWait)) - goto error; - if (xenfb_switch_state(&xenfb->kbd, XenbusStateInitWait)) - goto error; - - if (xenfb_hotplug(&xenfb->fb) < 0) - goto error; - if (xenfb_hotplug(&xenfb->kbd) < 0) - goto error; - - if (!xs_watch(xsh, xenfb->fb.otherend, "")) - goto error; - if (!xs_watch(xsh, xenfb->kbd.otherend, "")) - goto error; - - if (xenfb_wait_for_frontend_initialised(&xenfb->fb) < 0) - goto error; - if (xenfb_wait_for_frontend_initialised(&xenfb->kbd) < 0) - goto error; - - if (xenfb_bind(&xenfb->fb) < 0) - goto error; - if (xenfb_bind(&xenfb->kbd) < 0) - goto error; - - if (xenfb_xs_scanf1(xsh, xenfb->fb.otherend, "feature-update", - "%d", &val) < 0) - val = 0; - if (!val) { - errno = ENOTSUP; - goto error; - } - if (xenfb_xs_scanf1(xsh, xenfb->fb.otherend, "protocol", "%63s", - xenfb->protocol) < 0) - xenfb->protocol[0] = ''\0''; - xenfb_xs_printf(xsh, xenfb->fb.nodename, "request-update", "1"); - - /* TODO check for permitted ranges */ - fb_page = xenfb->fb.page; - xenfb->data.depth = fb_page->depth; - xenfb->data.width = fb_page->width; - xenfb->data.height = fb_page->height; - /* TODO check for consistency with the above */ - xenfb->data.len = fb_page->mem_length; - xenfb->data.row_stride = fb_page->line_length; - - if (xenfb_map_fb(xenfb, domid) < 0) - goto error; - - if (xenfb_switch_state(&xenfb->fb, XenbusStateConnected)) - goto error; - if (xenfb_switch_state(&xenfb->kbd, XenbusStateConnected)) - goto error; - - if (xenfb_wait_for_frontend_connected(&xenfb->kbd) < 0) - goto error; - if (xenfb_xs_scanf1(xsh, xenfb->kbd.otherend, "request-abs-pointer", - "%d", &val) < 0) - val = 0; - xenfb->data.abs_pointer_wanted = val; - - /* Listen for events from xenstore */ - if (qemu_set_fd_handler2(xs_fileno(xenfb->xsh), NULL, xenfb_dispatch_store, NULL, xenfb) < 0) - goto error; - - /* Listen for events from the event channel */ - if (qemu_set_fd_handler2(xc_evtchn_fd(xenfb->evt_xch), NULL, xenfb_dispatch_channel, NULL, xenfb) < 0) - goto error; - + } +} + + +/* Register 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_put_keycode, xenfb); qemu_add_mouse_event_handler(xenfb_mouse_event, xenfb, xenfb->data.abs_pointer_wanted, "Xen PVFB Mouse"); - xenfb->ds = ds; - /* Tell QEMU to allocate a graphical console */ - graphic_console_init(ds, + graphic_console_init(xenfb->ds, xenfb_update, xenfb_invalidate, xenfb_screen_dump, xenfb); - dpy_resize(ds, xenfb->data.width, xenfb->data.height); - - return 0; - - error: + dpy_resize(xenfb->ds, xenfb->data.width, xenfb->data.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; +} + +/* Process the frontend framebuffer config */ +static int xenfb_read_frontend_fb_config(struct xenfb *xenfb) { + struct xenfb_page *fb_page; + 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->data.depth = fb_page->depth; + xenfb->data.width = fb_page->width; + xenfb->data.height = fb_page->height; + /* TODO check for consistency with the above */ + xenfb->data.len = fb_page->mem_length; + xenfb->data.row_stride = fb_page->line_length; + 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->data.abs_pointer_wanted = val; + + return 0; +} + +/* Register a watch against a frontend device, and setup + * QEMU event loop to poll the xenstore FD for notification */ +static int xenfb_wait_for_frontend(struct xenfb_device *dev, IOHandler *handler) +{ + 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; +} + + +/* 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 */ +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; +} + +/* Callback invoked while waiting for KBD frontend to change + * to the connected state */ +void xenfb_frontend_connected_kbd(void *opaque) +{ + struct xenfb_device *dev = (struct xenfb_device *)opaque; + int ret = xenfb_frontend_connected(dev); + if (ret < 0) { + xenfb_shutdown(dev->xenfb); + 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); +} + +/* Callback invoked while waiting for FB frontend to change + * to the initialized state */ +void xenfb_frontend_initialized_fb(void *opaque) +{ + struct xenfb_device *dev = (struct xenfb_device *)opaque; + int ret = xenfb_frontend_initialized(dev); + if (ret < 0) { + xenfb_shutdown(dev->xenfb); + 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 initialized state */ +void xenfb_frontend_initialized_kbd(void *opaque) +{ + struct xenfb_device *dev = (struct xenfb_device *)opaque; + int ret = xenfb_frontend_initialized(dev); + if (ret < 0) { + xenfb_shutdown(dev->xenfb); + 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 backend to change + * to the created state */ +void xenfb_backend_created_fb(void *opaque) +{ + struct xenfb_device *dev = (struct xenfb_device *)opaque; + int ret = xenfb_backend_created(dev); + if (ret < 0) { + xenfb_shutdown(dev->xenfb); + 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 backend to change + * to the created state */ +void xenfb_backend_created_kbd(void *opaque) +{ + struct xenfb_device *dev = (struct xenfb_device *)opaque; + int ret = xenfb_backend_created(dev); + if (ret < 0) { + xenfb_shutdown(dev->xenfb); + 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); +} + + +/* Create a new Xen FB associated with QEMU DisplayState, + * wait for domid to appear and connect to its frontend */ +struct xenfb *xenfb_new(int domid, DisplayState *ds) +{ + int serrno; + struct xenfb *xenfb = qemu_malloc(sizeof(struct xenfb)); + + if (xenfb == NULL) + return NULL; + + memset(xenfb, 0, sizeof(*xenfb)); + xenfb->ds = ds; + xenfb->evt_xch = xenfb->xc = -1; + xenfb_device_init(&xenfb->fb, "vfb", xenfb); + xenfb_device_init(&xenfb->kbd, "vkbd", xenfb); + + xenfb->evt_xch = xc_evtchn_open(); + if (xenfb->evt_xch == -1) + goto fail; + + xenfb->xc = xc_interface_open(); + if (xenfb->xc == -1) + goto fail; + + xenfb->xsh = xs_daemon_open(); + if (!xenfb->xsh) + goto fail; + + xenfb_device_set_domain(&xenfb->fb, domid); + xenfb_device_set_domain(&xenfb->kbd, domid); + + 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_shutdown(xenfb); + errno = serrno; + return NULL; +} + +/* Remove the backend area in xenbus since the framebuffer really is + going away. */ +void xenfb_shutdown(struct xenfb *xenfb) +{ + 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); - xenfb_dev_fatal(&xenfb->fb, serrno, "on fire"); - xenfb_dev_fatal(&xenfb->kbd, serrno, "on fire"); - errno = serrno; - return -1; + if (xenfb->xc >= 0) + xc_interface_close(xenfb->xc); + if (xenfb->evt_xch >= 0) + xc_evtchn_close(xenfb->evt_xch); + if (xenfb->xsh) + xs_daemon_close(xenfb->xsh); + free(xenfb); } /* diff -r 90a6b110dc00 tools/ioemu/hw/xenfb.h --- a/tools/ioemu/hw/xenfb.h Tue Aug 14 15:46:31 2007 -0400 +++ b/tools/ioemu/hw/xenfb.h Tue Aug 14 16:33:46 2007 -0400 @@ -7,10 +7,7 @@ struct xenfb; -struct xenfb *xenfb_new(void); -void xenfb_delete(struct xenfb *xenfb); -void xenfb_teardown(struct xenfb *xenfb); - -int xenfb_attach_dom(struct xenfb *xenfb, int domid, DisplayState *ds); +struct xenfb *xenfb_new(int domid, DisplayState *ds); +void xenfb_shutdown(struct xenfb *xenfb); #endif -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=| _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel P. Berrange
2007-Aug-15 20:10 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. The xenconsoled daemon is no longer needed for guest consoles with this change applied. The code for the xen_console.c is based on the original tools/console/daemon/io.c, but greatly simplified - since its only dealing with a single guest there''s no state tracking to worry about. b/tools/ioemu/hw/xen_console.c | 424 ++++++++++++++++++++++++++++++++++++++++ b/tools/ioemu/hw/xen_console.h | 25 ++ tools/ioemu/Makefile.target | 1 tools/ioemu/hw/xen_machine_pv.c | 9 tools/ioemu/xenstore.c | 2 5 files changed, 460 insertions(+), 1 deletion(-) Signed-off-by: Daniel P. Berrange <berrange@redhat.com> Dan. diff -r 04c80f1aa008 tools/ioemu/Makefile.target --- a/tools/ioemu/Makefile.target Wed Aug 15 14:17:34 2007 -0400 +++ b/tools/ioemu/Makefile.target Wed Aug 15 15:06:54 2007 -0400 @@ -403,6 +403,7 @@ VL_OBJS+= xen_machine_fv.o VL_OBJS+= xen_machine_fv.o VL_OBJS+= xen_machine_pv.o VL_OBJS+= xenfb.o +VL_OBJS+= xen_console.o VL_OBJS+= tpm_tis.o CPPFLAGS += -DHAS_AUDIO endif diff -r 04c80f1aa008 tools/ioemu/hw/xen_console.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/ioemu/hw/xen_console.c Wed Aug 15 15:33:12 2007 -0400 @@ -0,0 +1,424 @@ +/* + * Copyright (C) International Business Machines Corp., 2005 + * Author(s): Anthony Liguori <aliguori@us.ibm.com> + * + * Copyright (C) Red Hat 2007 + * + * Xen Console + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <xs.h> +#include <xen/io/console.h> +#include <xenctrl.h> + +#include <malloc.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <sys/select.h> +#include <fcntl.h> +#include <unistd.h> +#include <termios.h> +#include <stdarg.h> +#include <sys/mman.h> +#include "vl.h" + +#include "xen_console.h" + +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +/* Each 10 bits takes ~ 3 digits, plus one, plus one for nul terminator. */ +#define MAX_STRLEN(x) ((sizeof(x) * CHAR_BIT + CHAR_BIT-1) / 10 * 3 + 2) + +#define dolog(val, fmt, ...) fprintf(stderr, fmt "\n", ## __VA_ARGS__) + +struct buffer +{ + uint8_t *data; + size_t consumed; + size_t size; + size_t capacity; + size_t max_capacity; +}; + +struct domain +{ + int domid; + struct buffer buffer; + + char *conspath; + char *serialpath; + int use_consolepath; + int ring_ref; + evtchn_port_t local_port; + evtchn_port_t remote_port; + int xce_handle; + struct xs_handle *xsh; + struct xencons_interface *interface; + CharDriverState *chr; +}; + + +static void buffer_append(struct domain *dom) +{ + struct buffer *buffer = &dom->buffer; + XENCONS_RING_IDX cons, prod, size; + struct xencons_interface *intf = dom->interface; + + cons = intf->out_cons; + prod = intf->out_prod; + mb(); + + size = prod - cons; + if ((size == 0) || (size > sizeof(intf->out))) + return; + + if ((buffer->capacity - buffer->size) < size) { + buffer->capacity += (size + 1024); + buffer->data = realloc(buffer->data, buffer->capacity); + if (buffer->data == NULL) { + dolog(LOG_ERR, "Memory allocation failed"); + exit(ENOMEM); + } + } + + while (cons != prod) + buffer->data[buffer->size++] = intf->out[ + MASK_XENCONS_IDX(cons++, intf->out)]; + + mb(); + intf->out_cons = cons; + xc_evtchn_notify(dom->xce_handle, dom->local_port); + + if (buffer->max_capacity && + buffer->size > buffer->max_capacity) { + /* Discard the middle of the data. */ + + size_t over = buffer->size - buffer->max_capacity; + uint8_t *maxpos = buffer->data + buffer->max_capacity; + + memmove(maxpos - over, maxpos, over); + buffer->data = realloc(buffer->data, buffer->max_capacity); + buffer->size = buffer->capacity = buffer->max_capacity; + + if (buffer->consumed > buffer->max_capacity - over) + buffer->consumed = buffer->max_capacity - over; + } +} + +static void buffer_advance(struct buffer *buffer, size_t len) +{ + buffer->consumed += len; + if (buffer->consumed == buffer->size) { + buffer->consumed = 0; + buffer->size = 0; + } +} + +/* Takes tuples of names, scanf-style args, and void **, NULL terminated. */ +int xs_gather(struct xs_handle *xs, const char *dir, ...) +{ + va_list ap; + const char *name; + char *path; + int ret = 0; + + va_start(ap, dir); + while (ret == 0 && (name = va_arg(ap, char *)) != NULL) { + const char *fmt = va_arg(ap, char *); + void *result = va_arg(ap, void *); + char *p; + + if (asprintf(&path, "%s/%s", dir, name) == -1) { + ret = ENOMEM; + break; + } + p = xs_read(xs, XBT_NULL, path, NULL); + free(path); + if (p == NULL) { + ret = ENOENT; + break; + } + if (fmt) { + if (sscanf(p, fmt, result) == 0) + ret = EINVAL; + free(p); + } else + *(char **)result = p; + } + va_end(ap); + return ret; +} + +static int domain_create_ring(struct domain *dom) +{ + int err, remote_port, ring_ref, rc; + + err = xs_gather(dom->xsh, dom->serialpath, + "ring-ref", "%u", &ring_ref, + "port", "%i", &remote_port, + NULL); + if (err) { + err = xs_gather(dom->xsh, dom->conspath, + "ring-ref", "%u", &ring_ref, + "port", "%i", &remote_port, + NULL); + if (err) { + fprintf(stderr, "Console: failed to find ring-ref/port yet\n"); + goto out; + } + dom->use_consolepath = 1; + } else + dom->use_consolepath = 0; + fprintf(stderr, "Console: got ring-ref %d port %d\n", ring_ref, remote_port); + + if ((ring_ref == dom->ring_ref) && (remote_port == dom->remote_port)) + goto out; + + if (ring_ref != dom->ring_ref) { + if (dom->interface != NULL) + munmap(dom->interface, getpagesize()); + dom->interface = xc_map_foreign_range( + xc_handle, dom->domid, getpagesize(), + PROT_READ|PROT_WRITE, + (unsigned long)ring_ref); + if (dom->interface == NULL) { + err = -errno; + goto out; + } + dom->ring_ref = ring_ref; + } + + dom->local_port = -1; + dom->remote_port = -1; + + dom->xce_handle = xc_evtchn_open(); + if (dom->xce_handle == -1) { + err = -errno; + goto out; + } + + rc = xc_evtchn_bind_interdomain(dom->xce_handle, + dom->domid, remote_port); + + if (rc == -1) { + err = -errno; + xc_evtchn_close(dom->xce_handle); + dom->xce_handle = -1; + goto out; + } + dom->local_port = rc; + dom->remote_port = remote_port; + + out: + return err; +} + + +static struct domain *create_domain(int domid, CharDriverState *chr) +{ + struct domain *dom; + char *s; + + dom = (struct domain *)malloc(sizeof(struct domain)); + if (dom == NULL) { + dolog(LOG_ERR, "Out of memory %s:%s():L%d", + __FILE__, __FUNCTION__, __LINE__); + exit(ENOMEM); + } + + dom->domid = domid; + dom->chr = chr; + + dom->xsh = xs_daemon_open(); + if (dom->xsh == NULL) { + fprintf(logfile, "Could not contact xenstore for console watch\n"); + goto out; + } + + dom->serialpath = xs_get_domain_path(dom->xsh, dom->domid); + s = realloc(dom->serialpath, strlen(dom->serialpath) + + strlen("/serial/0") + 1); + if (s == NULL) + goto out; + dom->serialpath = s; + strcat(dom->serialpath, "/serial/0"); + + dom->conspath = xs_get_domain_path(dom->xsh, dom->domid); + s = realloc(dom->conspath, strlen(dom->conspath) + + strlen("/console") + 1); + if (s == NULL) + goto out; + dom->conspath = s; + strcat(dom->conspath, "/console"); + + dom->buffer.data = 0; + dom->buffer.consumed = 0; + dom->buffer.size = 0; + dom->buffer.capacity = 0; + dom->buffer.max_capacity = 0; + + dom->ring_ref = -1; + dom->local_port = -1; + dom->remote_port = -1; + dom->interface = NULL; + dom->xce_handle = -1; + + + return dom; + out: + free(dom->serialpath); + free(dom->conspath); + free(dom); + return NULL; +} + + +static int ring_free_bytes(struct domain *dom) +{ + struct xencons_interface *intf = dom->interface; + XENCONS_RING_IDX cons, prod, space; + + cons = intf->in_cons; + prod = intf->in_prod; + mb(); + + space = prod - cons; + if (space > sizeof(intf->in)) + return 0; /* ring is screwed: ignore it */ + + return (sizeof(intf->in) - space); +} + +static int xencons_can_receive(void *opaque) +{ + struct domain *dom = (struct domain *)opaque; + + return ring_free_bytes(dom); +} + +static void xencons_receive(void *opaque, const uint8_t *buf, int len) +{ + struct domain *dom = (struct domain *)opaque; + int i, max; + struct xencons_interface *intf = dom->interface; + XENCONS_RING_IDX prod; + + max = ring_free_bytes(dom); + /* The can_receive() func limits this, but check again anyway */ + if (max < len) + len = max; + + prod = intf->in_prod; + for (i = 0; i < len; i++) { + intf->in[MASK_XENCONS_IDX(prod++, intf->in)] + buf[i]; + } + wmb(); + intf->in_prod = prod; + xc_evtchn_notify(dom->xce_handle, dom->local_port); +} + +static void xencons_send(struct domain *dom) +{ + ssize_t len; + len = qemu_chr_write(dom->chr, dom->buffer.data + dom->buffer.consumed, + dom->buffer.size - dom->buffer.consumed); + if (len < 1) { + /* + * Disable log because if we''re redirecting to /dev/pts/N we + * don''t want to flood logs when no client has the PTY open + */ + /* + dolog(LOG_DEBUG, "Write failed on domain %d: %zd, %d\n", + dom->domid, len, errno); + */ + } else { + buffer_advance(&dom->buffer, len); + } +} + +static void xencons_ring_read(void *opaque) +{ + evtchn_port_t port; + struct domain *dom = (struct domain *)opaque; + + if ((port = xc_evtchn_pending(dom->xce_handle)) == -1) + return; + + buffer_append(dom); + + (void)xc_evtchn_unmask(dom->xce_handle, port); + + if (dom->buffer.size - dom->buffer.consumed) + xencons_send(dom); +} + +static void xencons_startup(void *opaque) +{ + struct domain *dom = (struct domain *)opaque; + unsigned dummy; + char **vec; + int err; + vec = xs_read_watch(dom->xsh, &dummy); + if (vec) + free(vec); + fprintf(stderr, "Console: got watch\n"); + err = domain_create_ring(dom); + if (err) + return; + + xs_unwatch(dom->xsh, dom->conspath, ""); + xs_unwatch(dom->xsh, dom->serialpath, ""); + qemu_set_fd_handler2(xs_fileno(dom->xsh), NULL, NULL, NULL, NULL); + + fprintf(stderr, "Console: connected to guest frontend\n"); + if (qemu_set_fd_handler2(dom->xce_handle, NULL, xencons_ring_read, NULL, dom) < 0) + return; + + qemu_chr_add_handlers(dom->chr, xencons_can_receive, xencons_receive, + NULL, dom); +} + + +int xencons_init(int domid, CharDriverState *chr) +{ + struct domain *dom = create_domain(domid, chr); + + if (!dom) + return -1; + + /* Setup watches so we asynchronously connect to serial console */ + xs_watch(dom->xsh, dom->conspath, ""); + xs_watch(dom->xsh, dom->serialpath, ""); + qemu_set_fd_handler2(xs_fileno(dom->xsh), NULL, xencons_startup, NULL, dom); + fprintf(stderr, "Console: prepared domain, waiting for ringref at %s or %s\n", + dom->conspath, dom->serialpath); + + return 0; +} + + +/* + * Local variables: + * c-file-style: "linux" + * indent-tabs-mode: t + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff -r 04c80f1aa008 tools/ioemu/hw/xen_console.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/ioemu/hw/xen_console.h Wed Aug 15 15:06:54 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 04c80f1aa008 tools/ioemu/hw/xen_machine_pv.c --- a/tools/ioemu/hw/xen_machine_pv.c Wed Aug 15 14:17:34 2007 -0400 +++ b/tools/ioemu/hw/xen_machine_pv.c Wed Aug 15 15:06:54 2007 -0400 @@ -23,6 +23,7 @@ */ #include "vl.h" +#include "xen_console.h" #include "xenfb.h" @@ -39,6 +40,14 @@ static void xen_init_pv(uint64_t ram_siz { struct xenfb *xenfb; extern int domid; + + /* Connect to text console */ + if (serial_hds[0]) { + if (xencons_init(domid, serial_hds[0]) < 0) { + fprintf(stderr, "Could not connect to domain console\n"); + exit(1); + } + } /* Prepare PVFB state */ xenfb = xenfb_new(domid, ds); diff -r 04c80f1aa008 tools/ioemu/xenstore.c --- a/tools/ioemu/xenstore.c Wed Aug 15 14:17:34 2007 -0400 +++ b/tools/ioemu/xenstore.c Wed Aug 15 15:06:54 2007 -0400 @@ -17,7 +17,7 @@ #include <sys/stat.h> #include <fcntl.h> -static struct xs_handle *xsh = NULL; +struct xs_handle *xsh = NULL; static char *media_filename[MAX_DISKS + MAX_SCSI_DISKS]; static QEMUTimer *insert_timer = NULL; -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=| _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel P. Berrange
2007-Aug-15 20:11 UTC
Re: [Xen-devel] PATCH: 9/10: XenD device model re-factoring
This code re-factors the image.py class, unifying the paravirt and fullvirt cases to a large degree. Both PV & FV now have a ''device model'' - provided by same QEMU-DM binary in both cases. We pass -M xenpv, or -M xenfv as needed. The args for VNC, SDL etc are shared by both. HVM adds a bunch of extra args for disks & NICs mostly. The vfbif.py class no longer needs to start its own daemon for the paravirt framebuffer, since this is taken care of by the QEMU now. XendDomainInfo is tweaked so that it also starts the device model when restoring a paravirt guest. XendDomainInfo.py | 7 - image.py | 367 +++++++++++++++++++++++++++--------------------------- server/vfbif.py | 59 -------- 3 files changed, 192 insertions(+), 241 deletions(-) Signed-off-by: Daniel P. Berrange <berrange@redhat.com> Dan. diff -r fda4d94ca31d tools/python/xen/xend/image.py --- a/tools/python/xen/xend/image.py Tue Aug 14 19:55:04 2007 -0400 +++ b/tools/python/xen/xend/image.py Wed Aug 15 11:25:20 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. + model. The method destroy() is called when the domain is destroyed. - The default is to do nothing. """ ostype = None @@ -91,6 +90,17 @@ class ImageHandler: ("image/cmdline", self.cmdline), ("image/ramdisk", self.ramdisk)) + self.dmargs = self.parseDeviceModelArgs(vmConfig) + self.device_model = vmConfig[''platform''].get(''device_model'') + if not self.device_model: + self.device_model = xen.util.auxbin.pathTo("qemu-dm") + + 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 +183,135 @@ 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.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 + # 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 - + # 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 + 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()) class LinuxImageHandler(ImageHandler): @@ -223,6 +343,19 @@ class LinuxImageHandler(ImageHandler): ramdisk = self.ramdisk, features = self.vm.getFeatures()) + def parseDeviceModelArgs(self, vmConfig): + ret = ImageHandler.parseDeviceModelArgs(self, vmConfig) + # Equivalent to old xenconsoled behaviour. Should make + # it configurable in future + ret = ret + ["-serial", "pty"] + return ret + + def getDeviceModelArgs(self, restore = False): + args = ImageHandler.getDeviceModelArgs(self, restore) + args = args + ([ "-M", "xenpv"]) + return args + + class PPC_LinuxImageHandler(LinuxImageHandler): ostype = "linux" @@ -256,15 +389,6 @@ class HVMImageHandler(ImageHandler): if ''hvm'' not in info[''xen_caps'']: raise HVMRequired() - self.dmargs = self.parseDeviceModelArgs(vmConfig) - self.device_model = vmConfig[''platform''].get(''device_model'') - if not self.device_model: - raise VmError("hvm: missing device model") - - self.display = vmConfig[''platform''].get(''display'') - self.xauthority = vmConfig[''platform''].get(''xauthority'') - self.vncconsole = vmConfig[''platform''].get(''vncconsole'') - rtc_timeoffset = vmConfig[''platform''].get(''rtc_timeoffset'') self.vm.storeVm(("image/dmargs", " ".join(self.dmargs)), @@ -272,46 +396,17 @@ class HVMImageHandler(ImageHandler): ("image/display", self.display)) self.vm.storeVm(("rtc/timeoffset", rtc_timeoffset)) - self.pid = None - self.pae = int(vmConfig[''platform''].get(''pae'', 0)) self.apic = int(vmConfig[''platform''].get(''apic'', 0)) self.acpi = int(vmConfig[''platform''].get(''acpi'', 0)) - - - def buildDomain(self): - store_evtchn = self.vm.getStorePort() - - mem_mb = self.getRequiredInitialReservation() / 1024 - - log.debug("domid = %d", self.vm.getDomid()) - log.debug("image = %s", self.kernel) - log.debug("store_evtchn = %d", store_evtchn) - log.debug("memsize = %d", mem_mb) - log.debug("vcpus = %d", self.vm.getVCpuCount()) - log.debug("pae = %d", self.pae) - log.debug("acpi = %d", self.acpi) - log.debug("apic = %d", self.apic) - - rc = xc.hvm_build(domid = self.vm.getDomid(), - image = self.kernel, - store_evtchn = store_evtchn, - memsize = mem_mb, - vcpus = self.vm.getVCpuCount(), - pae = self.pae, - acpi = self.acpi, - apic = self.apic) - rc[''notes''] = { ''SUSPEND_CANCEL'': 1 } - return rc - - # Return a list of cmd line args to the device models based on the - # xm config file + def parseDeviceModelArgs(self, vmConfig): + ret = ImageHandler.parseDeviceModelArgs(self, vmConfig) + ret = ret + [''-vcpus'', str(self.vm.getVCpuCount())] + dmargs = [ ''boot'', ''fda'', ''fdb'', ''soundhw'', ''localtime'', ''serial'', ''stdvga'', ''isa'', - ''acpi'', ''usb'', ''usbdevice'', ''keymap'' ] - - ret = [''-vcpus'', str(self.vm.getVCpuCount())] + ''acpi'', ''usb'', ''usbdevice'' ] for a in dmargs: v = vmConfig[''platform''].get(a) @@ -340,7 +435,6 @@ class HVMImageHandler(ImageHandler): # Handle disk/network related options mac = None - ret = ret + ["-domain-name", str(self.vm.info[''name_label''])] nics = 0 for devuuid in vmConfig[''vbd_refs'']: @@ -369,130 +463,40 @@ class HVMImageHandler(ImageHandler): ret.append("-net") ret.append("tap,vlan=%d,bridge=%s" % (nics, bridge)) - - # - # Find RFB console device, and if it exists, make QEMU enable - # the VNC console. - # - if int(vmConfig[''platform''].get(''nographic'', 0)) != 0: - # skip vnc init if nographic is set - ret.append(''-nographic'') - return ret - - vnc_config = {} - has_vnc = int(vmConfig[''platform''].get(''vnc'', 0)) != 0 - has_sdl = int(vmConfig[''platform''].get(''sdl'', 0)) != 0 - for dev_uuid in vmConfig[''console_refs'']: - dev_type, dev_info = vmConfig[''devices''][dev_uuid] - if dev_type == ''vfb'': - vnc_config = dev_info.get(''other_config'', {}) - has_vnc = True - break - - if has_vnc: - if not vnc_config: - for key in (''vncunused'', ''vnclisten'', ''vncdisplay'', - ''vncpasswd''): - if key in vmConfig[''platform'']: - vnc_config[key] = vmConfig[''platform''][key] - - vnclisten = vnc_config.get(''vnclisten'', - xenopts().get_vnclisten_address()) - vncdisplay = vnc_config.get(''vncdisplay'', 0) - ret.append(''-vnc'') - ret.append("%s:%d" % (vnclisten, vncdisplay)) - - if vnc_config.get(''vncunused'', 0): - ret.append(''-vncunused'') - - # Store vncpassword in xenstore - vncpasswd = vnc_config.get(''vncpasswd'') - if not vncpasswd: - vncpasswd = xenopts().get_vncpasswd_default() - - if vncpasswd is None: - raise VmError(''vncpasswd is not setup in vmconfig or '' - ''xend-config.sxp'') - - if vncpasswd != '''': - self.vm.storeVm(''vncpasswd'', vncpasswd) - elif has_sdl: - # SDL is default in QEMU. - pass - else: - ret.append(''-nographic'') - - if int(vmConfig[''platform''].get(''monitor'', 0)) != 0: - ret = ret + [''-monitor'', ''vc''] return ret - def createDeviceModel(self, restore = False): - if self.pid: - return - # Execute device model. - #todo: Error handling - args = [self.device_model] - args = args + ([ "-d", "%d" % self.vm.getDomid() ]) - if arch.type == "ia64": - args = args + ([ "-m", "%s" % - (self.getRequiredInitialReservation() / 1024) ]) - args = args + self.dmargs + def getDeviceModelArgs(self, restore = False): + args = ImageHandler.getDeviceModelArgs(self, restore) + args = args + ([ "-M", "xenfv"]) if restore: args = args + ([ "-loadvm", "/var/lib/xen/qemu-save.%d" % self.vm.getDomid() ]) - env = dict(os.environ) - if self.display: - env[''DISPLAY''] = self.display - if self.xauthority: - env[''XAUTHORITY''] = self.xauthority - if self.vncconsole: - args = args + ([ "-vncviewer" ]) - log.info("spawning device models: %s %s", self.device_model, args) - # keep track of pid and spawned options to kill it later - self.pid = os.spawnve(os.P_NOWAIT, self.device_model, args, env) - self.vm.storeDom("image/device-model-pid", self.pid) - log.info("device model pid: %d", self.pid) - - def saveDeviceModel(self): - # Signal the device model to pause itself and save its state - xstransact.Store("/local/domain/0/device-model/%i" - % self.vm.getDomid(), (''command'', ''save'')) - # Wait for confirmation. Could do this with a watch but we''d - # still end up spinning here waiting for the watch to fire. - state = '''' - count = 0 - while state != ''paused'': - state = xstransact.Read("/local/domain/0/device-model/%i/state" - % self.vm.getDomid()) - time.sleep(0.1) - count += 1 - if count > 100: - raise VmError(''Timed out waiting for device model to save'') - - def resumeDeviceModel(self): - # Signal the device model to resume activity after pausing to save. - xstransact.Store("/local/domain/0/device-model/%i" - % self.vm.getDomid(), (''command'', ''continue'')) - - def recreate(self): - self.pid = self.vm.gatherDom((''image/device-model-pid'', int)) - - def destroy(self, suspend = False): - if self.pid and not suspend: - try: - os.kill(self.pid, signal.SIGKILL) - except OSError, exn: - log.exception(exn) - try: - os.waitpid(self.pid, 0) - except OSError, exn: - # This is expected if Xend has been restarted within the - # life of this domain. In this case, we can kill the process, - # but we can''t wait for it because it''s not our child. - pass - self.pid = None - state = xstransact.Remove("/local/domain/0/device-model/%i" - % self.vm.getDomid()) + return args + + def buildDomain(self): + store_evtchn = self.vm.getStorePort() + + mem_mb = self.getRequiredInitialReservation() / 1024 + + log.debug("domid = %d", self.vm.getDomid()) + log.debug("image = %s", self.kernel) + log.debug("store_evtchn = %d", store_evtchn) + log.debug("memsize = %d", mem_mb) + log.debug("vcpus = %d", self.vm.getVCpuCount()) + log.debug("pae = %d", self.pae) + log.debug("acpi = %d", self.acpi) + log.debug("apic = %d", self.apic) + + rc = xc.hvm_build(domid = self.vm.getDomid(), + image = self.kernel, + store_evtchn = store_evtchn, + memsize = mem_mb, + vcpus = self.vm.getVCpuCount(), + pae = self.pae, + acpi = self.acpi, + apic = self.apic) + rc[''notes''] = { ''SUSPEND_CANCEL'': 1 } + return rc class IA64_HVM_ImageHandler(HVMImageHandler): @@ -514,6 +518,13 @@ class IA64_HVM_ImageHandler(HVMImageHand def getRequiredShadowMemory(self, shadow_mem_kb, maxmem_kb): # Explicit shadow memory is not a concept return 0 + + def getDeviceModelArgs(self, restore = False): + args = HVMImageHandler.getDeviceModelArgs(self, restore) + args = args + ([ "-m", "%s" % + (self.getRequiredInitialReservation() / 1024) ]) + return args + class X86_HVM_ImageHandler(HVMImageHandler): diff -r fda4d94ca31d tools/python/xen/xend/server/vfbif.py --- a/tools/python/xen/xend/server/vfbif.py Tue Aug 14 19:55:04 2007 -0400 +++ b/tools/python/xen/xend/server/vfbif.py Wed Aug 15 11:18:05 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''] @@ -42,57 +34,6 @@ class VfbifController(DevController): return dict([(CONFIG_ENTRIES[i], devinfo[i]) 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''): diff -r 04c80f1aa008 tools/python/xen/xend/XendDomainInfo.py --- a/tools/python/xen/xend/XendDomainInfo.py Wed Aug 15 14:17:34 2007 -0400 +++ b/tools/python/xen/xend/XendDomainInfo.py Wed Aug 15 15:28:38 2007 -0400 @@ -1638,10 +1638,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-Aug-15 20:12 UTC
Re: [Xen-devel] PATCH: 10/10: Gut the xenconsoled daemon
This patch guts the xenconsoled daemon, removing all code related to processing the paravirt guest text console. This capability is now provided by QEMU so using a separate daemon is redundant. The only thing left in xenconsoled is the code for persistently logging the hypervisor messages. If this isn''t desired, then there is no need to launch xenconsoled at all. In fact this code could easily just be pushed into XenD it is so small. a/tools/console/daemon/io.c | 831 ------------------------------------------- a/tools/console/daemon/io.h | 27 - tools/console/daemon/main.c | 62 ++- tools/console/daemon/utils.c | 28 - tools/console/daemon/utils.h | 3 5 files changed, 46 insertions(+), 905 deletions(-) Signed-off-by: Daniel P. Berrange <berrange@redhat.com> Dan. diff -r fda4d94ca31d tools/console/daemon/io.c --- a/tools/console/daemon/io.c Tue Aug 14 19:55:04 2007 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,831 +0,0 @@ -/* - * Copyright (C) International Business Machines Corp., 2005 - * Author(s): Anthony Liguori <aliguori@us.ibm.com> - * - * Xen Console Daemon - * - * 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 - */ - -#define _GNU_SOURCE - -#include "utils.h" -#include "io.h" -#include <xs.h> -#include <xen/io/console.h> -#include <xenctrl.h> - -#include <malloc.h> -#include <stdlib.h> -#include <errno.h> -#include <string.h> -#include <sys/select.h> -#include <fcntl.h> -#include <unistd.h> -#include <termios.h> -#include <stdarg.h> -#include <sys/mman.h> - -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) - -/* Each 10 bits takes ~ 3 digits, plus one, plus one for nul terminator. */ -#define MAX_STRLEN(x) ((sizeof(x) * CHAR_BIT + CHAR_BIT-1) / 10 * 3 + 2) - -extern int log_reload; -extern int log_guest; -extern int log_hv; -extern char *log_dir; - -static int log_hv_fd = -1; -static int xc_handle = -1; - -struct buffer -{ - char *data; - size_t consumed; - size_t size; - size_t capacity; - size_t max_capacity; -}; - -struct domain -{ - int domid; - int tty_fd; - int log_fd; - bool is_dead; - struct buffer buffer; - struct domain *next; - char *conspath; - char *serialpath; - int use_consolepath; - int ring_ref; - evtchn_port_t local_port; - evtchn_port_t remote_port; - int xce_handle; - struct xencons_interface *interface; -}; - -static struct domain *dom_head; - -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); - - /* Get the data to the logfile as early as possible because if - * no one is listening on the console pty then it will fill up - * and handle_tty_write will stop being called. - */ - if (dom->log_fd != -1) { - int len = write(dom->log_fd, - buffer->data + buffer->size - size, - size); - if (len < 0) - dolog(LOG_ERR, "Write to log failed on domain %d: %d (%s)\n", - dom->domid, errno, strerror(errno)); - } - - if (buffer->max_capacity && - buffer->size > buffer->max_capacity) { - /* Discard the middle of the data. */ - - size_t over = buffer->size - buffer->max_capacity; - char *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 bool buffer_empty(struct buffer *buffer) -{ - return buffer->size == 0; -} - -static void buffer_advance(struct buffer *buffer, size_t len) -{ - buffer->consumed += len; - if (buffer->consumed == buffer->size) { - buffer->consumed = 0; - buffer->size = 0; - } -} - -static bool domain_is_valid(int domid) -{ - bool ret; - xc_dominfo_t info; - - ret = (xc_domain_getinfo(xc, domid, 1, &info) == 1 && - info.domid == domid); - - return ret; -} - -static int create_hv_log(void) -{ - char logfile[PATH_MAX]; - int fd; - snprintf(logfile, PATH_MAX-1, "%s/hypervisor.log", log_dir); - logfile[PATH_MAX-1] = ''\0''; - - fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0644); - if (fd == -1) - dolog(LOG_ERR, "Failed to open log %s: %d (%s)", - logfile, errno, strerror(errno)); - return fd; -} - -static int create_domain_log(struct domain *dom) -{ - char logfile[PATH_MAX]; - char *namepath, *data, *s; - int fd; - unsigned int len; - - namepath = xs_get_domain_path(xs, dom->domid); - s = realloc(namepath, strlen(namepath) + 6); - if (s == NULL) { - free(namepath); - return -1; - } - namepath = s; - strcat(namepath, "/name"); - data = xs_read(xs, XBT_NULL, namepath, &len); - if (!data) - return -1; - if (!len) { - free(data); - return -1; - } - - snprintf(logfile, PATH_MAX-1, "%s/guest-%s.log", log_dir, data); - free(data); - logfile[PATH_MAX-1] = ''\0''; - - fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0644); - if (fd == -1) - dolog(LOG_ERR, "Failed to open log %s: %d (%s)", - logfile, errno, strerror(errno)); - return fd; -} - - -static int domain_create_tty(struct domain *dom) -{ - char *path; - int master; - bool success; - - if ((master = open("/dev/ptmx",O_RDWR|O_NOCTTY)) == -1 || - grantpt(master) == -1 || unlockpt(master) == -1) { - dolog(LOG_ERR, "Failed to create tty for domain-%d", - dom->domid); - master = -1; - } else { - const char *slave = ptsname(master); - struct termios term; - char *data; - unsigned int len; - - if (tcgetattr(master, &term) != -1) { - cfmakeraw(&term); - tcsetattr(master, TCSAFLUSH, &term); - } - - if (dom->use_consolepath) { - success = asprintf(&path, "%s/limit", dom->conspath) !- -1; - if (!success) - goto out; - data = xs_read(xs, XBT_NULL, path, &len); - if (data) { - dom->buffer.max_capacity = strtoul(data, 0, 0); - free(data); - } - free(path); - } - - success = asprintf(&path, "%s/limit", dom->serialpath) != -1; - if (!success) - goto out; - data = xs_read(xs, XBT_NULL, path, &len); - if (data) { - dom->buffer.max_capacity = strtoul(data, 0, 0); - free(data); - } - free(path); - - success = asprintf(&path, "%s/tty", dom->serialpath) != -1; - if (!success) - goto out; - success = xs_write(xs, XBT_NULL, path, slave, strlen(slave)); - free(path); - if (!success) - goto out; - - if (dom->use_consolepath) { - success = asprintf(&path, "%s/tty", dom->conspath) !- -1; - if (!success) - goto out; - success = xs_write(xs, XBT_NULL, path, slave, - strlen(slave)); - free(path); - if (!success) - goto out; - } - - if (fcntl(master, F_SETFL, O_NONBLOCK) == -1) - goto out; - } - - return master; - out: - close(master); - return -1; -} - -/* 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(xs, dom->serialpath, - "ring-ref", "%u", &ring_ref, - "port", "%i", &remote_port, - NULL); - if (err) { - err = xs_gather(xs, dom->conspath, - "ring-ref", "%u", &ring_ref, - "port", "%i", &remote_port, - NULL); - if (err) - goto out; - dom->use_consolepath = 1; - } else - dom->use_consolepath = 0; - - 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, dom->domid, getpagesize(), - PROT_READ|PROT_WRITE, - (unsigned long)ring_ref); - if (dom->interface == NULL) { - err = EINVAL; - goto out; - } - dom->ring_ref = ring_ref; - } - - dom->local_port = -1; - dom->remote_port = -1; - if (dom->xce_handle != -1) - xc_evtchn_close(dom->xce_handle); - - /* Opening evtchn independently for each console is a bit - * wasteful, but that''s how the code is structured... */ - 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; - - if (dom->tty_fd == -1) { - dom->tty_fd = domain_create_tty(dom); - - if (dom->tty_fd == -1) { - err = errno; - xc_evtchn_close(dom->xce_handle); - dom->xce_handle = -1; - dom->local_port = -1; - dom->remote_port = -1; - goto out; - } - } - - if (log_guest) - dom->log_fd = create_domain_log(dom); - - out: - return err; -} - -static bool watch_domain(struct domain *dom, bool watch) -{ - char domid_str[3 + MAX_STRLEN(dom->domid)]; - bool success; - - sprintf(domid_str, "dom%u", dom->domid); - if (watch) { - success = xs_watch(xs, dom->serialpath, domid_str); - if (success) { - success = xs_watch(xs, dom->conspath, domid_str); - if (success) - domain_create_ring(dom); - else - xs_unwatch(xs, dom->serialpath, domid_str); - } - } else { - success = xs_unwatch(xs, dom->serialpath, domid_str); - success = xs_unwatch(xs, dom->conspath, domid_str); - } - - return success; -} - - -static struct domain *create_domain(int domid) -{ - 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->serialpath = xs_get_domain_path(xs, 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(xs, 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->tty_fd = -1; - dom->log_fd = -1; - - dom->is_dead = false; - dom->buffer.data = 0; - dom->buffer.consumed = 0; - dom->buffer.size = 0; - dom->buffer.capacity = 0; - dom->buffer.max_capacity = 0; - dom->next = NULL; - - dom->ring_ref = -1; - dom->local_port = -1; - dom->remote_port = -1; - dom->interface = NULL; - dom->xce_handle = -1; - - if (!watch_domain(dom, true)) - goto out; - - dom->next = dom_head; - dom_head = dom; - - dolog(LOG_DEBUG, "New domain %d", domid); - - return dom; - out: - free(dom->serialpath); - free(dom->conspath); - free(dom); - return NULL; -} - -static struct domain *lookup_domain(int domid) -{ - struct domain *dom; - - for (dom = dom_head; dom; dom = dom->next) - if (dom->domid == domid) - return dom; - return NULL; -} - -static void remove_domain(struct domain *dom) -{ - struct domain **pp; - - dolog(LOG_DEBUG, "Removing domain-%d", dom->domid); - - for (pp = &dom_head; *pp; pp = &(*pp)->next) { - if (dom == *pp) { - *pp = dom->next; - free(dom); - break; - } - } -} - -static void cleanup_domain(struct domain *d) -{ - if (d->tty_fd != -1) { - close(d->tty_fd); - d->tty_fd = -1; - } - if (d->log_fd != -1) { - close(d->log_fd); - d->log_fd = -1; - } - - free(d->buffer.data); - d->buffer.data = NULL; - - free(d->serialpath); - d->serialpath = NULL; - - free(d->conspath); - d->conspath = NULL; - - remove_domain(d); -} - -static void shutdown_domain(struct domain *d) -{ - d->is_dead = true; - watch_domain(d, false); - if (d->interface != NULL) - munmap(d->interface, getpagesize()); - d->interface = NULL; - if (d->xce_handle != -1) - xc_evtchn_close(d->xce_handle); - d->xce_handle = -1; - cleanup_domain(d); -} - -void enum_domains(void) -{ - int domid = 1; - xc_dominfo_t dominfo; - struct domain *dom; - - while (xc_domain_getinfo(xc, domid, 1, &dominfo) == 1) { - dom = lookup_domain(dominfo.domid); - if (dominfo.dying) { - if (dom) - shutdown_domain(dom); - } else { - if (dom == NULL) - create_domain(dominfo.domid); - } - domid = dominfo.domid + 1; - } -} - -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 void handle_tty_read(struct domain *dom) -{ - ssize_t len = 0; - char msg[80]; - int i; - struct xencons_interface *intf = dom->interface; - XENCONS_RING_IDX prod; - - len = ring_free_bytes(dom); - if (len == 0) - return; - - if (len > sizeof(msg)) - len = sizeof(msg); - - len = read(dom->tty_fd, msg, len); - if (len < 1) { - close(dom->tty_fd); - dom->tty_fd = -1; - - if (domain_is_valid(dom->domid)) { - dom->tty_fd = domain_create_tty(dom); - } else { - shutdown_domain(dom); - } - } else if (domain_is_valid(dom->domid)) { - prod = intf->in_prod; - for (i = 0; i < len; i++) { - intf->in[MASK_XENCONS_IDX(prod++, intf->in)] - msg[i]; - } - wmb(); - intf->in_prod = prod; - xc_evtchn_notify(dom->xce_handle, dom->local_port); - } else { - close(dom->tty_fd); - dom->tty_fd = -1; - shutdown_domain(dom); - } -} - -static void handle_tty_write(struct domain *dom) -{ - ssize_t len; - - len = write(dom->tty_fd, dom->buffer.data + dom->buffer.consumed, - dom->buffer.size - dom->buffer.consumed); - if (len < 1) { - dolog(LOG_DEBUG, "Write failed on domain %d: %zd, %d\n", - dom->domid, len, errno); - - close(dom->tty_fd); - dom->tty_fd = -1; - - if (domain_is_valid(dom->domid)) { - dom->tty_fd = domain_create_tty(dom); - } else { - shutdown_domain(dom); - } - } else { - buffer_advance(&dom->buffer, len); - } -} - -static void handle_ring_read(struct domain *dom) -{ - evtchn_port_t port; - - if ((port = xc_evtchn_pending(dom->xce_handle)) == -1) - return; - - buffer_append(dom); - - (void)xc_evtchn_unmask(dom->xce_handle, port); -} - -static void handle_xs(void) -{ - char **vec; - int domid; - struct domain *dom; - unsigned int num; - - vec = xs_read_watch(xs, &num); - if (!vec) - return; - - if (!strcmp(vec[XS_WATCH_TOKEN], "domlist")) - enum_domains(); - else if (sscanf(vec[XS_WATCH_TOKEN], "dom%u", &domid) == 1) { - dom = lookup_domain(domid); - /* We may get watches firing for domains that have recently - been removed, so dom may be NULL here. */ - if (dom && dom->is_dead == false) - domain_create_ring(dom); - } - - free(vec); -} - -static void handle_hv_logs(void) -{ - char buffer[1024*16]; - char *bufptr = buffer; - unsigned int size = sizeof(buffer); - if (xc_readconsolering(xc_handle, &bufptr, &size, 1) == 0) { - int len = write(log_hv_fd, buffer, size); - if (len < 0) - dolog(LOG_ERR, "Failed to write hypervisor log: %d (%s)", - errno, strerror(errno)); - } -} - -static void handle_log_reload(void) -{ - if (log_guest) { - struct domain *d; - for (d = dom_head; d; d = d->next) { - if (d->log_fd != -1) - close(d->log_fd); - d->log_fd = create_domain_log(d); - } - } - - if (log_hv) { - if (log_hv_fd != -1) - close(log_hv_fd); - log_hv_fd = create_hv_log(); - } -} - -void handle_io(void) -{ - fd_set readfds, writefds; - int ret; - - if (log_hv) { - xc_handle = xc_interface_open(); - if (xc_handle == -1) - dolog(LOG_ERR, "Failed to open xc handle: %d (%s)", - errno, strerror(errno)); - else - log_hv_fd = create_hv_log(); - } - - for (;;) { - struct domain *d, *n; - struct timeval timeout = { 1, 0 }; /* Read HV logs every 1 second */ - int max_fd = -1; - - FD_ZERO(&readfds); - FD_ZERO(&writefds); - - FD_SET(xs_fileno(xs), &readfds); - max_fd = MAX(xs_fileno(xs), max_fd); - - for (d = dom_head; d; d = d->next) { - if (d->xce_handle != -1) { - int evtchn_fd = xc_evtchn_fd(d->xce_handle); - FD_SET(evtchn_fd, &readfds); - max_fd = MAX(evtchn_fd, max_fd); - } - - if (d->tty_fd != -1) { - if (!d->is_dead && ring_free_bytes(d)) - FD_SET(d->tty_fd, &readfds); - - if (!buffer_empty(&d->buffer)) - FD_SET(d->tty_fd, &writefds); - max_fd = MAX(d->tty_fd, max_fd); - } - } - - /* XXX I wish we didn''t have to busy wait for hypervisor logs - * but there''s no obvious way to get event channel notifications - * for new HV log data as we can with guest */ - ret = select(max_fd + 1, &readfds, &writefds, 0, - log_hv_fd != -1 ? &timeout : NULL); - - if (log_reload) { - handle_log_reload(); - log_reload = 0; - } - - /* Abort if select failed, except for EINTR cases - which indicate a possible log reload */ - if (ret == -1) { - if (errno == EINTR) - continue; - dolog(LOG_ERR, "Failure in select: %d (%s)", - errno, strerror(errno)); - break; - } - - /* Always process HV logs even if not a timeout */ - if (log_hv_fd != -1) - handle_hv_logs(); - - /* Must not check returned FDSET if it was a timeout */ - if (ret == 0) - continue; - - if (FD_ISSET(xs_fileno(xs), &readfds)) - handle_xs(); - - for (d = dom_head; d; d = n) { - n = d->next; - if (d->xce_handle != -1 && - FD_ISSET(xc_evtchn_fd(d->xce_handle), &readfds)) - handle_ring_read(d); - - if (d->tty_fd != -1 && FD_ISSET(d->tty_fd, &readfds)) - handle_tty_read(d); - - if (d->tty_fd != -1 && FD_ISSET(d->tty_fd, &writefds)) - handle_tty_write(d); - - if (d->is_dead) - cleanup_domain(d); - } - } - - if (log_hv_fd != -1) { - close(log_hv_fd); - log_hv_fd = -1; - } - if (xc_handle != -1) { - xc_interface_close(xc_handle); - xc_handle = -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 fda4d94ca31d tools/console/daemon/io.h --- a/tools/console/daemon/io.h Tue Aug 14 19:55:04 2007 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -/*\ - * Copyright (C) International Business Machines Corp., 2005 - * Author(s): Anthony Liguori <aliguori@us.ibm.com> - * - * Xen Console Daemon - * - * 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 -\*/ - -#ifndef CONSOLED_IO_H -#define CONSOLED_IO_H - -void enum_domains(void); -void handle_io(void); - -#endif diff -r fda4d94ca31d tools/console/daemon/main.c --- a/tools/console/daemon/main.c Tue Aug 14 19:55:04 2007 -0400 +++ b/tools/console/daemon/main.c Tue Aug 14 20:09:28 2007 -0400 @@ -26,15 +26,14 @@ #include <string.h> #include <signal.h> #include <sys/types.h> +#include <limits.h> +#include <fcntl.h> #include "xenctrl.h" #include "utils.h" -#include "io.h" int log_reload = 0; -int log_guest = 0; -int log_hv = 0; char *log_dir = NULL; static void handle_hup(int sig) @@ -44,13 +43,41 @@ static void handle_hup(int sig) static void usage(char *name) { - printf("Usage: %s [-h] [-V] [-v] [-i] [--log=none|guest|hv|all] [--log-dir=DIR] [--pid-file=PATH]\n", name); + printf("Usage: %s [-h] [-V] [-v] [-i] [--log-dir=DIR] [--pid-file=PATH]\n", name); } static void version(char *name) { printf("Xen Console Daemon 3.0\n"); } + +static int create_hv_log(void) +{ + char logfile[PATH_MAX]; + int fd; + snprintf(logfile, PATH_MAX-1, "%s/hypervisor.log", log_dir); + logfile[PATH_MAX-1] = ''\0''; + + fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0644); + if (fd == -1) + dolog(LOG_ERR, "Failed to open log %s: %d (%s)", + logfile, errno, strerror(errno)); + return fd; +} + +static void handle_hv_logs(int log_hv_fd) +{ + char buffer[1024*16]; + char *bufptr = buffer; + unsigned int size = sizeof(buffer); + if (xc_readconsolering(xc, &bufptr, &size, 1) == 0) { + int len = write(log_hv_fd, buffer, size); + if (len < 0) + dolog(LOG_ERR, "Failed to write hypervisor log: %d (%s)", + errno, strerror(errno)); + } +} + int main(int argc, char **argv) { @@ -60,7 +87,6 @@ int main(int argc, char **argv) { "version", 0, 0, ''V'' }, { "verbose", 0, 0, ''v'' }, { "interactive", 0, 0, ''i'' }, - { "log", 1, 0, ''l'' }, { "log-dir", 1, 0, ''r'' }, { "pid-file", 1, 0, ''p'' }, { 0 }, @@ -71,6 +97,7 @@ int main(int argc, char **argv) int syslog_mask = LOG_WARNING; int opt_ind = 0; char *pidfile = NULL; + int log_hv_fd = -1; while ((ch = getopt_long(argc, argv, sopts, lopts, &opt_ind)) != -1) { switch (ch) { @@ -86,16 +113,6 @@ int main(int argc, char **argv) break; case ''i'': is_interactive = true; - break; - case ''l'': - if (!strcmp(optarg, "all")) { - log_hv = 1; - log_guest = 1; - } else if (!strcmp(optarg, "hv")) { - log_hv = 1; - } else if (!strcmp(optarg, "guest")) { - log_guest = 1; - } break; case ''r'': log_dir = strdup(optarg); @@ -132,9 +149,20 @@ int main(int argc, char **argv) if (!xen_setup()) exit(1); - enum_domains(); + log_hv_fd = create_hv_log(); - handle_io(); + for (;;) { + /* Wish we didn''t have to spin for HV logs */ + sleep(1); + + if (log_reload) { + close(log_hv_fd); + log_hv_fd = create_hv_log(); + log_reload = 0; + } + + handle_hv_logs(log_hv_fd); + } closelog(); free(log_dir); diff -r fda4d94ca31d tools/console/daemon/utils.c --- a/tools/console/daemon/utils.c Tue Aug 14 19:55:04 2007 -0400 +++ b/tools/console/daemon/utils.c Tue Aug 14 19:59:38 2007 -0400 @@ -36,7 +36,6 @@ #include "xenctrl.h" #include "utils.h" -struct xs_handle *xs; int xc; static void child_exit(int sig) @@ -107,37 +106,12 @@ void daemonize(const char *pidfile) bool xen_setup(void) { - - xs = xs_daemon_open(); - if (xs == NULL) { - dolog(LOG_ERR, - "Failed to contact xenstore (%m). Is it running?"); - goto out; - } - xc = xc_interface_open(); if (xc == -1) { dolog(LOG_ERR, "Failed to contact hypervisor (%m)"); - goto out; - } - - if (!xs_watch(xs, "@introduceDomain", "domlist")) { - dolog(LOG_ERR, "xenstore watch on @introduceDomain fails."); - goto out; - } - - if (!xs_watch(xs, "@releaseDomain", "domlist")) { - dolog(LOG_ERR, "xenstore watch on @releaseDomain fails."); - goto out; + return false; } return true; - - out: - if (xs) - xs_daemon_close(xs); - if (xc != -1) - xc_interface_close(xc); - return false; } diff -r fda4d94ca31d tools/console/daemon/utils.h --- a/tools/console/daemon/utils.h Tue Aug 14 19:55:04 2007 -0400 +++ b/tools/console/daemon/utils.h Tue Aug 14 19:59:51 2007 -0400 @@ -25,12 +25,9 @@ #include <syslog.h> #include <stdio.h> -#include "xs.h" - void daemonize(const char *pidfile); bool xen_setup(void); -extern struct xs_handle *xs; extern int xc; #if 1 -- |=- 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
Keir Fraser
2007-Aug-16 07:30 UTC
Re: [Xen-devel] PATCH: 0/10: Merge xenfb & xenconsoled into qemu-dm
On 15/8/07 21:00, "Daniel P. Berrange" <berrange@redhat.com> wrote:> The only feature this re-factoring looses is the ability to have the paravirt > text console persistently logged to a file. QEMU allows us to specify that > a character device is either sent to a PTY, or a file, but not both at the > same time. I''m thinking about ways in which QEMU''s character device config > syntax & drivers may be extended to allow use of a PTY & File concurrently. > > The patches should be applied in order - after each individual patch you > should still have a fully operational system for both FV & PV.Have you tested both HVM and PV guests with save/restore, migration, and *failed* save/restore (e.g., by forcing an error in xc_domain_save.c)? The last needs care because qemu-dm must be kept around until the last moment, in case the save or migration fails. Are these patches intended to be applied now, or are they RFC? -- Keir _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel P. Berrange
2007-Aug-16 12:49 UTC
Re: [Xen-devel] PATCH: 0/10: Merge xenfb & xenconsoled into qemu-dm
On Thu, Aug 16, 2007 at 08:30:08AM +0100, Keir Fraser wrote:> On 15/8/07 21:00, "Daniel P. Berrange" <berrange@redhat.com> wrote: > > > The only feature this re-factoring looses is the ability to have the paravirt > > text console persistently logged to a file. QEMU allows us to specify that > > a character device is either sent to a PTY, or a file, but not both at the > > same time. I''m thinking about ways in which QEMU''s character device config > > syntax & drivers may be extended to allow use of a PTY & File concurrently. > > > > The patches should be applied in order - after each individual patch you > > should still have a fully operational system for both FV & PV. > > Have you tested both HVM and PV guests with save/restore, migration, and > *failed* save/restore (e.g., by forcing an error in xc_domain_save.c)? The > last needs care because qemu-dm must be kept around until the last moment, > in case the save or migration fails.I''ve not tested failed save/restore or migration - just normal save/restore for FV & PV. I''ll do some further testing of the scenarios you suggest. I don''t think I should have broken anything in qemu-dm for HVM because in the HVM codepaths I merely moved code from one file to another.> Are these patches intended to be applied now, or are they RFC?They could be applied now, but was expecting people might have some feedback /recommendations for changes - Christian normally has lots of good comments for QEMU related stuff. So if I have to do another revision of the patches I''m fine with it. 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
Keir Fraser
2007-Aug-16 12:54 UTC
Re: [Xen-devel] PATCH: 0/10: Merge xenfb & xenconsoled into qemu-dm
On 16/8/07 13:49, "Daniel P. Berrange" <berrange@redhat.com> wrote:>> Are these patches intended to be applied now, or are they RFC? > > They could be applied now, but was expecting people might have some feedback > /recommendations for changes - Christian normally has lots of good comments > for QEMU related stuff. So if I have to do another revision of the patches > I''m fine with it.My own feeling is that the xenfb merge is very sensible, but I don''t see much of a win from merging xenconsoled, and the downside is that you then need a qemu-dm instance for every PV guest. I think that requiring qemu-dm for more ''featureful'' PV guests -- framebuffer, USB, etc -- is well and good, but someone who is running more minimal domU configurations -- console, net, block -- isn''t going to want or welcome the rather unnecessary per-domU overhead of qemu-dm. So I think that qemu-dm for PV guests should be optional, and automatically enabled only if a config option that requires qemu is enabled. -- Keir _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel P. Berrange
2007-Aug-16 15:34 UTC
Re: [Xen-devel] PATCH: 0/10: Merge xenfb & xenconsoled into qemu-dm
On Thu, Aug 16, 2007 at 01:54:04PM +0100, Keir Fraser wrote:> On 16/8/07 13:49, "Daniel P. Berrange" <berrange@redhat.com> wrote: > > >> Are these patches intended to be applied now, or are they RFC? > > > > They could be applied now, but was expecting people might have some feedback > > /recommendations for changes - Christian normally has lots of good comments > > for QEMU related stuff. So if I have to do another revision of the patches > > I''m fine with it. > > My own feeling is that the xenfb merge is very sensible, but I don''t see > much of a win from merging xenconsoled, and the downside is that you then > need a qemu-dm instance for every PV guest. I think that requiring qemu-dm > for more ''featureful'' PV guests -- framebuffer, USB, etc -- is well and > good, but someone who is running more minimal domU configurations -- > console, net, block -- isn''t going to want or welcome the rather unnecessary > per-domU overhead of qemu-dm.Yep, I can see that would be useful for some folks working in constrained environments. Of course they probably don''t want the XenD overhead either, but that''s a can of worms I won''t get into right now ;-) Thinking about this, I think I can easily re-work the last two patches so that xenconsoled will continue to process the guest consoles, if-and-only-if the guest doesn''t have a QEMU instance already doing it. That would give us choice between both deployment scenarios per-guest. 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
Keir Fraser
2007-Aug-16 16:04 UTC
Re: [Xen-devel] PATCH: 0/10: Merge xenfb & xenconsoled into qemu-dm
On 16/8/07 16:34, "Daniel P. Berrange" <berrange@redhat.com> wrote:>> My own feeling is that the xenfb merge is very sensible, but I don''t see >> much of a win from merging xenconsoled, and the downside is that you then >> need a qemu-dm instance for every PV guest. I think that requiring qemu-dm >> for more ''featureful'' PV guests -- framebuffer, USB, etc -- is well and >> good, but someone who is running more minimal domU configurations -- >> console, net, block -- isn''t going to want or welcome the rather unnecessary >> per-domU overhead of qemu-dm. > > Yep, I can see that would be useful for some folks working in constrained > environments. Of course they probably don''t want the XenD overhead either, > but that''s a can of worms I won''t get into right now ;-)At least the xend overhead is largely one-off rather than per-domain.> Thinking about this, I think I can easily re-work the last two patches so > that xenconsoled will continue to process the guest consoles, if-and-only-if > the guest doesn''t have a QEMU instance already doing it. That would give us > choice between both deployment scenarios per-guest.That seems fair. The guest-console-over-vnc scenario is a compelling argument for supporting console-in-qemu as an option. -- Keir _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Pat Campbell
2007-Aug-16 16:13 UTC
Re: [Xen-devel] PATCH: 0/10: Merge xenfb & xenconsoled into qemu-dm
>>> On Thu, Aug 16, 2007 at 9:34 AM, in message<20070816153415.GH16779@redhat.com>, "Daniel P. Berrange" <berrange@redhat.com> wrote:> On Thu, Aug 16, 2007 at 01:54:04PM +0100, Keir Fraser wrote: >> On 16/8/07 13:49, "Daniel P. Berrange" <berrange@redhat.com> wrote: >> >> >> Are these patches intended to be applied now, or are they RFC? >> > >> > They could be applied now, but was expecting people might have some > feedback >> > /recommendations for changes - Christian normally has lots of good comments >> > for QEMU related stuff. So if I have to do another revision of the patches >> > I''m fine with it. >> >> My own feeling is that the xenfb merge is very sensible, but I don''t see >> much of a win from merging xenconsoled, and the downside is that you then >> need a qemu- dm instance for every PV guest. I think that requiring qemu- dm >> for more ''featureful'' PV guests -- framebuffer, USB, etc -- is well and >> good, but someone who is running more minimal domU configurations -- >> console, net, block -- isn''t going to want or welcome the rather unnecessary >> per- domU overhead of qemu- dm. > > Yep, I can see that would be useful for some folks working in constrained > environments. Of course they probably don''t want the XenD overhead either, > but that''s a can of worms I won''t get into right now ;- ) > > Thinking about this, I think I can easily re- work the last two patches so > that xenconsoled will continue to process the guest consoles, if- and- only- if > the guest doesn''t have a QEMU instance already doing it. That would give us > choice between both deployment scenarios per- guest. > > Regards, > Dan.Would this patch set, in it''s current state, allow a ''featureful'' PV guest to see a DOM0 CDROM as a CD device instead of a block device? Thanks Pat _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Keir Fraser
2007-Aug-16 16:17 UTC
Re: [Xen-devel] PATCH: 0/10: Merge xenfb & xenconsoled into qemu-dm
On 16/8/07 17:13, "Pat Campbell" <plc@novell.com> wrote:>> Yep, I can see that would be useful for some folks working in constrained >> environments. Of course they probably don''t want the XenD overhead either, >> but that''s a can of worms I won''t get into right now ;- ) >> >> Thinking about this, I think I can easily re- work the last two patches so >> that xenconsoled will continue to process the guest consoles, if- and- only- >> if >> the guest doesn''t have a QEMU instance already doing it. That would give us >> choice between both deployment scenarios per- guest. > > Would this patch set, in it''s current state, allow a ''featureful'' PV guest to > see a > DOM0 CDROM as a CD device instead of a block device?No, that kind of stuff isn''t plumbed through at all. But it''s an obvious direction to take it. -- Keir _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel P. Berrange
2007-Aug-16 16:21 UTC
Re: [Xen-devel] PATCH: 0/10: Merge xenfb & xenconsoled into qemu-dm
On Thu, Aug 16, 2007 at 05:17:37PM +0100, Keir Fraser wrote:> On 16/8/07 17:13, "Pat Campbell" <plc@novell.com> wrote: > > >> Yep, I can see that would be useful for some folks working in constrained > >> environments. Of course they probably don''t want the XenD overhead either, > >> but that''s a can of worms I won''t get into right now ;- ) > >> > >> Thinking about this, I think I can easily re- work the last two patches so > >> that xenconsoled will continue to process the guest consoles, if- and- only- > >> if > >> the guest doesn''t have a QEMU instance already doing it. That would give us > >> choice between both deployment scenarios per- guest. > > > > Would this patch set, in it''s current state, allow a ''featureful'' PV guest to > > see a > > DOM0 CDROM as a CD device instead of a block device? > > No, that kind of stuff isn''t plumbed through at all. But it''s an obvious > direction to take it.Yes, I''d particularly like to be able get the emulated USB bus hooked up, but personally have no clue how to go about doing this. It gives a very nice device passthrough capability that will integrate extremely well with HAL & desktop session policy allowing users to assign their local hotplugged devices to the guest as VMWare Workstation allows. 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
Mark Williamson
2007-Aug-16 19:43 UTC
Re: [Xen-devel] PATCH: 0/10: Merge xenfb & xenconsoled into qemu-dm
> Yes, I''d particularly like to be able get the emulated USB bus hooked up, > but personally have no clue how to go about doing this. > > It gives a very nice device passthrough capability that will integrate > extremely well with HAL & desktop session policy allowing users to assign > their local hotplugged devices to the guest as VMWare Workstation allows.IBM were interested in this kind of stuff too; their bladecenter has a single USB cdrom for a group of blades. The drive is simply switched between them using a USB switcher in the blade enclosure and standard hotplug on the blade OS. The ability to do the same thing *within* a blade, to different OSes would make management more uniform for them. They did have someone looking at getting paravirt USB working but I''m not sure where that project got to. However, if USB could easily be passed to paravirt guests as an emulated device it would be quite handy for some things. It would be interesting to see what performance was achievable this way, but some high bandwidth devices like disk and network can always go through the usual paravirt drivers. Cheers, Mark -- Dave: Just a question. What use is a unicyle with no seat? And no pedals! Mark: To answer a question with a question: What use is a skateboard? Dave: Skateboards have wheels. Mark: My wheel has a wheel! _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
In response to the cdrom discussion going on today: Attached is a port of a patch we have against 3.1 This patch plumbs the cdrom info through QEMU such that a QEMU monitor command may switch the domain owning the physiical cdrom, such that an eject command on the guest command line will physically eject the drive door. Monitor command example: set_cdrom_owner 1 hdd (for the time being the "hdd" parameter is a constant, as we only support a singular CDRom) Signed-off-by: Ben Guthro <bguthro@virtualiron.com> Signed-off-by: Joshua Nicholas <jnicholas@virtualiron.com> _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel P. Berrange
2007-Aug-17 20:12 UTC
Re: [Xen-devel] PATCH: 0/10: Merge xenfb & xenconsoled into qemu-dm
On Thu, Aug 16, 2007 at 04:34:15PM +0100, Daniel P. Berrange wrote:> On Thu, Aug 16, 2007 at 01:54:04PM +0100, Keir Fraser wrote: > > On 16/8/07 13:49, "Daniel P. Berrange" <berrange@redhat.com> wrote: > > > > >> Are these patches intended to be applied now, or are they RFC? > > > > > > They could be applied now, but was expecting people might have some feedback > > > /recommendations for changes - Christian normally has lots of good comments > > > for QEMU related stuff. So if I have to do another revision of the patches > > > I''m fine with it. > > > > My own feeling is that the xenfb merge is very sensible, but I don''t see > > much of a win from merging xenconsoled, and the downside is that you then > > need a qemu-dm instance for every PV guest. I think that requiring qemu-dm > > for more ''featureful'' PV guests -- framebuffer, USB, etc -- is well and > > good, but someone who is running more minimal domU configurations -- > > console, net, block -- isn''t going to want or welcome the rather unnecessary > > per-domU overhead of qemu-dm. > > Yep, I can see that would be useful for some folks working in constrained > environments. Of course they probably don''t want the XenD overhead either, > but that''s a can of worms I won''t get into right now ;-) > > Thinking about this, I think I can easily re-work the last two patches so > that xenconsoled will continue to process the guest consoles, if-and-only-if > the guest doesn''t have a QEMU instance already doing it. That would give us > choice between both deployment scenarios per-guest.I''ve got this working ok - since both xenconsoled and qemu-dm are already reading the /local/domain/<id>/console/ path in xenstore, I simply added an extra field ''use-device-model'' which can be 1 or 0. If XenD sees that a PV domain has a device model then it sets it to 1, causing xenconsoled to ignore that guest. I''ll post patches to this effect over the weekend Dan. -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=| _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Daniel P. Berrange
2007-Aug-17 20:14 UTC
Re: [Xen-devel] PATCH: 0/10: Merge xenfb & xenconsoled into qemu-dm
On Thu, Aug 16, 2007 at 01:49:39PM +0100, Daniel P. Berrange wrote:> On Thu, Aug 16, 2007 at 08:30:08AM +0100, Keir Fraser wrote: > > On 15/8/07 21:00, "Daniel P. Berrange" <berrange@redhat.com> wrote: > > > > > The only feature this re-factoring looses is the ability to have the paravirt > > > text console persistently logged to a file. QEMU allows us to specify that > > > a character device is either sent to a PTY, or a file, but not both at the > > > same time. I''m thinking about ways in which QEMU''s character device config > > > syntax & drivers may be extended to allow use of a PTY & File concurrently. > > > > > > The patches should be applied in order - after each individual patch you > > > should still have a fully operational system for both FV & PV. > > > > Have you tested both HVM and PV guests with save/restore, migration, and > > *failed* save/restore (e.g., by forcing an error in xc_domain_save.c)? The > > last needs care because qemu-dm must be kept around until the last moment, > > in case the save or migration fails. > > I''ve not tested failed save/restore or migration - just normal save/restore > for FV & PV. I''ll do some further testing of the scenarios you suggest. I > don''t think I should have broken anything in qemu-dm for HVM because in the > HVM codepaths I merely moved code from one file to another.Migration was working fine, but there''s some complications with recovering from a failed save attempt. In fact even without my changes it currently fails being unable to detach the blktap disk, and so the recovery dies with a ''Device vbd already connected'' error. Once I track that problem down I know what changes I need to make PVFB recovery work 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
Keir Fraser
2007-Aug-18 10:11 UTC
Re: [Xen-devel] PATCH: 0/10: Merge xenfb & xenconsoled into qemu-dm
On 17/8/07 21:12, "Daniel P. Berrange" <berrange@redhat.com> wrote:>> Thinking about this, I think I can easily re-work the last two patches so >> that xenconsoled will continue to process the guest consoles, if-and-only-if >> the guest doesn''t have a QEMU instance already doing it. That would give us >> choice between both deployment scenarios per-guest. > > I''ve got this working ok - since both xenconsoled and qemu-dm are already > reading the /local/domain/<id>/console/ path in xenstore, I simply added > an extra field ''use-device-model'' which can be 1 or 0. If XenD sees that > a PV domain has a device model then it sets it to 1, causing xenconsoled > to ignore that guest. I''ll post patches to this effect over the weekendSounds basically good, but a field called ''type'' in the backend xenstore directory would be more flexible and more consistent with other backend directory contents (at least netback''s). We could use values ''ioemu'' and ''xenconsoled'', and absence of the field implies xenconsoled. Both ioemu and xenconsoled should check the field. -- Keir _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel