ia64/xen-unstable

changeset 17082:c6eeb71a85cf

Enable HVM guest VT-d device hotplug via a simple ACPI hotplug device model.

** Currently only 2 virtual hotplug pci slots(6~7) are created so more
than 2 vtd dev can't be hotplugged, but we can easily extend it in
future.

Three new commands are added:
"xm pci-list domid" show the current assigned vtd device, like:
VSlt domain bus slot func
0x6 0x0 0x02 0x00 0x0

"xm pci-detach" hot remove the specified vtd device by the virtual
slot, like:
xm pci-detach EdwinHVMDomainVtd 6

"xm pci-attach DomainID dom bus dev func [vslot]" hot add a new vtd
device in the vslot. If no vslot specified, a free slot will be picked
up. e.g. to insert '0000:03:00.0':
xm pci-attach EdwinHVMDomainVtd 0 3 0 0

** guest pci hotplug
linux: pls. use 2.6.X and enable ACPI PCI hotplug ( Bus options=> PCI
hotplug => ACPI PCI hotplug driver )
windows: 2000/xp/2003/vista are all okay

Signed-off-by: Zhai Edwin <edwin.zhai@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Feb 15 14:13:17 2008 +0000 (2008-02-15)
parents 29c03bc32d3e
children 819399d0bdb1
files tools/firmware/hvmloader/acpi/dsdt.asl tools/firmware/hvmloader/acpi/dsdt.c tools/firmware/hvmloader/acpi/static_tables.c tools/ioemu/hw/pass-through.c tools/ioemu/hw/pc.c tools/ioemu/hw/pci.c tools/ioemu/hw/piix4acpi.c tools/ioemu/monitor.c tools/ioemu/vl.c tools/ioemu/vl.h tools/ioemu/xenstore.c tools/libxc/xc_domain.c tools/libxc/xenctrl.h tools/python/xen/xend/XendDomainInfo.py tools/python/xen/xend/image.py tools/python/xen/xend/server/DevController.py tools/python/xen/xend/server/pciif.py tools/python/xen/xm/main.py xen/arch/x86/domctl.c xen/arch/x86/hvm/irq.c xen/arch/x86/hvm/vmx/vtd/intel-iommu.c xen/arch/x86/hvm/vmx/vtd/io.c xen/include/asm-x86/hvm/irq.h xen/include/asm-x86/iommu.h xen/include/public/domctl.h xen/include/public/hvm/ioreq.h
line diff
     1.1 --- a/tools/firmware/hvmloader/acpi/dsdt.asl	Fri Feb 15 12:50:55 2008 +0000
     1.2 +++ b/tools/firmware/hvmloader/acpi/dsdt.asl	Fri Feb 15 14:13:17 2008 +0000
     1.3 @@ -86,7 +86,7 @@ DefinitionBlock ("DSDT.aml", "DSDT", 2, 
     1.4             Name (_UID, 0x00)
     1.5             Name (_ADR, 0x00)
     1.6             Name (_BBN, 0x00)
     1.7 - 
     1.8 +
     1.9             Method (_CRS, 0, NotSerialized)
    1.10             {
    1.11                 Name (PRT0, ResourceTemplate ()
    1.12 @@ -720,6 +720,121 @@ DefinitionBlock ("DSDT.aml", "DSDT", 2, 
    1.13                      })
    1.14                  } 
    1.15              }
    1.16 +
    1.17 +            /******************************************************************
    1.18 +             * Each PCI hotplug slot needs at least two methods to handle
    1.19 +             * the ACPI event:
    1.20 +             *  _EJ0: eject a device
    1.21 +             *  _STA: return a device's status, e.g. enabled or removed
    1.22 +             * Other methods are optional: 
    1.23 +             *  _PS0/3: put them here for debug purpose
    1.24 +             * 
    1.25 +             * Eject button would generate a general-purpose event, then the
    1.26 +             * control method for this event uses Notify() to inform OSPM which
    1.27 +             * action happened and on which device.
    1.28 +             *
    1.29 +             * Pls. refer "6.3 Device Insertion, Removal, and Status Objects"
    1.30 +             * in ACPI spec 3.0b for details.
    1.31 +             *
    1.32 +             * QEMU provides a simple hotplug controller with some I/O to
    1.33 +             * handle the hotplug action and status, which is beyond the ACPI
    1.34 +             * scope.
    1.35 +             */
    1.36 +
    1.37 +            Device (S1F0)
    1.38 +            {
    1.39 +                Name (_ADR, 0x00060000) /* Dev 6, Func 0 */
    1.40 +                Name (_SUN, 0x00000001)
    1.41 +
    1.42 +                Method (_PS0, 0)
    1.43 +                {
    1.44 +                    Store (0x80, \_GPE.DPT2)
    1.45 +                }
    1.46 +
    1.47 +                Method (_PS3, 0)
    1.48 +                {
    1.49 +                    Store (0x83, \_GPE.DPT2)
    1.50 +                }
    1.51 +
    1.52 +                Method (_EJ0, 1)
    1.53 +                {
    1.54 +                    Store (0x88, \_GPE.DPT2)
    1.55 +                    Store (0x1, \_GPE.PHP1) /* eject php slot 1*/
    1.56 +                }
    1.57 +
    1.58 +                Method (_STA, 0)
    1.59 +                {
    1.60 +                    Store (0x89, \_GPE.DPT2)
    1.61 +                    Return ( \_GPE.PHP1 )   /* IN status as the _STA */
    1.62 +                }
    1.63 +            }
    1.64 +
    1.65 +            Device (S2F0)
    1.66 +            {
    1.67 +                Name (_ADR, 0x00070000) /* Dev 7, Func 0 */
    1.68 +                Name (_SUN, 0x00000002)
    1.69 +
    1.70 +                Method (_PS0, 0)
    1.71 +                {
    1.72 +                    Store (0x90, \_GPE.DPT2)
    1.73 +                }
    1.74 +
    1.75 +                Method (_PS3, 0)
    1.76 +                {
    1.77 +                    Store (0x93, \_GPE.DPT2)
    1.78 +                }
    1.79 +
    1.80 +                Method (_EJ0, 1)
    1.81 +                {
    1.82 +                    Store (0x98, \_GPE.DPT2)
    1.83 +                    Store (0x1, \_GPE.PHP2) /* eject php slot 1*/
    1.84 +                }
    1.85 +
    1.86 +                Method (_STA, 0)
    1.87 +                {
    1.88 +                    Store (0x99, \_GPE.DPT2)
    1.89 +                    Return ( \_GPE.PHP2 )   /* IN status as the _STA */
    1.90 +                }
    1.91 +            }
    1.92 +        }
    1.93 +    }
    1.94 +
    1.95 +    Scope (\_GPE)
    1.96 +    {
    1.97 +        OperationRegion (PHP, SystemIO, 0x10c0, 0x03)
    1.98 +        Field (PHP, ByteAcc, NoLock, Preserve)
    1.99 +        {
   1.100 +            PSTA,   8, /* hotplug controller status reg */
   1.101 +            PHP1,   8, /* hotplug slot 1 control reg */
   1.102 +            PHP2,   8  /* hotplug slot 2 control reg */
   1.103 +        }
   1.104 +        OperationRegion (DG1, SystemIO, 0xb044, 0x04)
   1.105 +        Field (DG1, ByteAcc, NoLock, Preserve)
   1.106 +        {
   1.107 +            DPT1,   8,
   1.108 +            DPT2,   8
   1.109 +        }
   1.110 +        Method (_L03, 0, NotSerialized)
   1.111 +        {
   1.112 +            /* detect slot and event(remove/add) */
   1.113 +            Name (SLT, 0x0)
   1.114 +            Name (EVT, 0x0)
   1.115 +            Store (PSTA, Local1)
   1.116 +            ShiftRight (Local1, 0x4, SLT)
   1.117 +            And (Local1, 0xf, EVT)
   1.118 +
   1.119 +            /* debug */
   1.120 +            Store (SLT, DPT1)
   1.121 +            Store (EVT, DPT2)
   1.122 +
   1.123 +            If ( LEqual(SLT, 0x1) )
   1.124 +            {
   1.125 +                Notify (\_SB.PCI0.S1F0, EVT)
   1.126 +            }
   1.127 +            ElseIf ( LEqual(SLT, 0x2) )
   1.128 +            {
   1.129 +                Notify (\_SB.PCI0.S2F0, EVT)
   1.130 +            }
   1.131          }
   1.132      }
   1.133  }
     2.1 --- a/tools/firmware/hvmloader/acpi/dsdt.c	Fri Feb 15 12:50:55 2008 +0000
     2.2 +++ b/tools/firmware/hvmloader/acpi/dsdt.c	Fri Feb 15 14:13:17 2008 +0000
     2.3 @@ -5,15 +5,15 @@
     2.4   * Copyright (C) 2000 - 2006 Intel Corporation
     2.5   * Supports ACPI Specification Revision 3.0a
     2.6   * 
     2.7 - * Compilation of "dsdt.asl" - Fri Feb 15 12:48:58 2008
     2.8 + * Compilation of "dsdt.asl" - Fri Feb 15 14:07:57 2008
     2.9   * 
    2.10   * C source code output
    2.11   *
    2.12   */
    2.13  unsigned char AmlCode[] =
    2.14  {
    2.15 -    0x44,0x53,0x44,0x54,0x9C,0x0E,0x00,0x00,  /* 00000000    "DSDT...." */
    2.16 -    0x02,0xD5,0x58,0x65,0x6E,0x00,0x00,0x00,  /* 00000008    "..Xen..." */
    2.17 +    0x44,0x53,0x44,0x54,0x5A,0x10,0x00,0x00,  /* 00000000    "DSDTZ..." */
    2.18 +    0x02,0xCC,0x58,0x65,0x6E,0x00,0x00,0x00,  /* 00000008    "..Xen..." */
    2.19      0x48,0x56,0x4D,0x00,0x00,0x00,0x00,0x00,  /* 00000010    "HVM....." */
    2.20      0x00,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C,  /* 00000018    "....INTL" */
    2.21      0x07,0x07,0x06,0x20,0x08,0x50,0x4D,0x42,  /* 00000020    "... .PMB" */
    2.22 @@ -29,7 +29,7 @@ unsigned char AmlCode[] =
    2.23      0x07,0x0A,0x07,0x00,0x00,0x08,0x50,0x49,  /* 00000070    "......PI" */
    2.24      0x43,0x44,0x00,0x14,0x0C,0x5F,0x50,0x49,  /* 00000078    "CD..._PI" */
    2.25      0x43,0x01,0x70,0x68,0x50,0x49,0x43,0x44,  /* 00000080    "C.phPICD" */
    2.26 -    0x10,0x43,0xE1,0x5F,0x53,0x42,0x5F,0x5B,  /* 00000088    ".C._SB_[" */
    2.27 +    0x10,0x42,0xF1,0x5F,0x53,0x42,0x5F,0x5B,  /* 00000088    ".B._SB_[" */
    2.28      0x80,0x42,0x49,0x4F,0x53,0x00,0x0C,0x00,  /* 00000090    ".BIOS..." */
    2.29      0xA0,0x0E,0x00,0x0A,0x10,0x5B,0x81,0x21,  /* 00000098    ".....[.!" */
    2.30      0x42,0x49,0x4F,0x53,0x01,0x55,0x41,0x52,  /* 000000A0    "BIOS.UAR" */
    2.31 @@ -45,7 +45,7 @@ unsigned char AmlCode[] =
    2.32      0x00,0xFF,0xFF,0x09,0x00,0x00,0x00,0x00,  /* 000000F0    "........" */
    2.33      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  /* 000000F8    "........" */
    2.34      0x00,0x00,0x00,0x0A,0x00,0x00,0x00,0x00,  /* 00000100    "........" */
    2.35 -    0x00,0x79,0x00,0x5B,0x82,0x4F,0xD8,0x50,  /* 00000108    ".y.[.O.P" */
    2.36 +    0x00,0x79,0x00,0x5B,0x82,0x4E,0xE8,0x50,  /* 00000108    ".y.[.N.P" */
    2.37      0x43,0x49,0x30,0x08,0x5F,0x48,0x49,0x44,  /* 00000110    "CI0._HID" */
    2.38      0x0C,0x41,0xD0,0x0A,0x03,0x08,0x5F,0x55,  /* 00000118    ".A...._U" */
    2.39      0x49,0x44,0x00,0x08,0x5F,0x41,0x44,0x52,  /* 00000120    "ID.._ADR" */
    2.40 @@ -479,6 +479,62 @@ unsigned char AmlCode[] =
    2.41      0x54,0x41,0x00,0xA4,0x0A,0x0F,0x08,0x5F,  /* 00000E80    "TA....._" */
    2.42      0x43,0x52,0x53,0x11,0x10,0x0A,0x0D,0x47,  /* 00000E88    "CRS....G" */
    2.43      0x01,0x78,0x03,0x78,0x03,0x08,0x08,0x22,  /* 00000E90    ".x.x..."" */
    2.44 -    0x80,0x00,0x79,0x00,
    2.45 +    0x80,0x00,0x79,0x00,0x5B,0x82,0x4D,0x07,  /* 00000E98    "..y.[.M." */
    2.46 +    0x53,0x31,0x46,0x30,0x08,0x5F,0x41,0x44,  /* 00000EA0    "S1F0._AD" */
    2.47 +    0x52,0x0C,0x00,0x00,0x06,0x00,0x08,0x5F,  /* 00000EA8    "R......_" */
    2.48 +    0x53,0x55,0x4E,0x01,0x14,0x13,0x5F,0x50,  /* 00000EB0    "SUN..._P" */
    2.49 +    0x53,0x30,0x00,0x70,0x0A,0x80,0x5C,0x2E,  /* 00000EB8    "S0.p..\." */
    2.50 +    0x5F,0x47,0x50,0x45,0x44,0x50,0x54,0x32,  /* 00000EC0    "_GPEDPT2" */
    2.51 +    0x14,0x13,0x5F,0x50,0x53,0x33,0x00,0x70,  /* 00000EC8    ".._PS3.p" */
    2.52 +    0x0A,0x83,0x5C,0x2E,0x5F,0x47,0x50,0x45,  /* 00000ED0    "..\._GPE" */
    2.53 +    0x44,0x50,0x54,0x32,0x14,0x1F,0x5F,0x45,  /* 00000ED8    "DPT2.._E" */
    2.54 +    0x4A,0x30,0x01,0x70,0x0A,0x88,0x5C,0x2E,  /* 00000EE0    "J0.p..\." */
    2.55 +    0x5F,0x47,0x50,0x45,0x44,0x50,0x54,0x32,  /* 00000EE8    "_GPEDPT2" */
    2.56 +    0x70,0x01,0x5C,0x2E,0x5F,0x47,0x50,0x45,  /* 00000EF0    "p.\._GPE" */
    2.57 +    0x50,0x48,0x50,0x31,0x14,0x1E,0x5F,0x53,  /* 00000EF8    "PHP1.._S" */
    2.58 +    0x54,0x41,0x00,0x70,0x0A,0x89,0x5C,0x2E,  /* 00000F00    "TA.p..\." */
    2.59 +    0x5F,0x47,0x50,0x45,0x44,0x50,0x54,0x32,  /* 00000F08    "_GPEDPT2" */
    2.60 +    0xA4,0x5C,0x2E,0x5F,0x47,0x50,0x45,0x50,  /* 00000F10    ".\._GPEP" */
    2.61 +    0x48,0x50,0x31,0x5B,0x82,0x4E,0x07,0x53,  /* 00000F18    "HP1[.N.S" */
    2.62 +    0x32,0x46,0x30,0x08,0x5F,0x41,0x44,0x52,  /* 00000F20    "2F0._ADR" */
    2.63 +    0x0C,0x00,0x00,0x07,0x00,0x08,0x5F,0x53,  /* 00000F28    "......_S" */
    2.64 +    0x55,0x4E,0x0A,0x02,0x14,0x13,0x5F,0x50,  /* 00000F30    "UN...._P" */
    2.65 +    0x53,0x30,0x00,0x70,0x0A,0x90,0x5C,0x2E,  /* 00000F38    "S0.p..\." */
    2.66 +    0x5F,0x47,0x50,0x45,0x44,0x50,0x54,0x32,  /* 00000F40    "_GPEDPT2" */
    2.67 +    0x14,0x13,0x5F,0x50,0x53,0x33,0x00,0x70,  /* 00000F48    ".._PS3.p" */
    2.68 +    0x0A,0x93,0x5C,0x2E,0x5F,0x47,0x50,0x45,  /* 00000F50    "..\._GPE" */
    2.69 +    0x44,0x50,0x54,0x32,0x14,0x1F,0x5F,0x45,  /* 00000F58    "DPT2.._E" */
    2.70 +    0x4A,0x30,0x01,0x70,0x0A,0x98,0x5C,0x2E,  /* 00000F60    "J0.p..\." */
    2.71 +    0x5F,0x47,0x50,0x45,0x44,0x50,0x54,0x32,  /* 00000F68    "_GPEDPT2" */
    2.72 +    0x70,0x01,0x5C,0x2E,0x5F,0x47,0x50,0x45,  /* 00000F70    "p.\._GPE" */
    2.73 +    0x50,0x48,0x50,0x32,0x14,0x1E,0x5F,0x53,  /* 00000F78    "PHP2.._S" */
    2.74 +    0x54,0x41,0x00,0x70,0x0A,0x99,0x5C,0x2E,  /* 00000F80    "TA.p..\." */
    2.75 +    0x5F,0x47,0x50,0x45,0x44,0x50,0x54,0x32,  /* 00000F88    "_GPEDPT2" */
    2.76 +    0xA4,0x5C,0x2E,0x5F,0x47,0x50,0x45,0x50,  /* 00000F90    ".\._GPEP" */
    2.77 +    0x48,0x50,0x32,0x10,0x4E,0x0B,0x5F,0x47,  /* 00000F98    "HP2.N._G" */
    2.78 +    0x50,0x45,0x5B,0x80,0x50,0x48,0x50,0x5F,  /* 00000FA0    "PE[.PHP_" */
    2.79 +    0x01,0x0B,0xC0,0x10,0x0A,0x03,0x5B,0x81,  /* 00000FA8    "......[." */
    2.80 +    0x15,0x50,0x48,0x50,0x5F,0x01,0x50,0x53,  /* 00000FB0    ".PHP_.PS" */
    2.81 +    0x54,0x41,0x08,0x50,0x48,0x50,0x31,0x08,  /* 00000FB8    "TA.PHP1." */
    2.82 +    0x50,0x48,0x50,0x32,0x08,0x5B,0x80,0x44,  /* 00000FC0    "PHP2.[.D" */
    2.83 +    0x47,0x31,0x5F,0x01,0x0B,0x44,0xB0,0x0A,  /* 00000FC8    "G1_..D.." */
    2.84 +    0x04,0x5B,0x81,0x10,0x44,0x47,0x31,0x5F,  /* 00000FD0    ".[..DG1_" */
    2.85 +    0x01,0x44,0x50,0x54,0x31,0x08,0x44,0x50,  /* 00000FD8    ".DPT1.DP" */
    2.86 +    0x54,0x32,0x08,0x14,0x46,0x07,0x5F,0x4C,  /* 00000FE0    "T2..F._L" */
    2.87 +    0x30,0x33,0x00,0x08,0x53,0x4C,0x54,0x5F,  /* 00000FE8    "03..SLT_" */
    2.88 +    0x00,0x08,0x45,0x56,0x54,0x5F,0x00,0x70,  /* 00000FF0    "..EVT_.p" */
    2.89 +    0x50,0x53,0x54,0x41,0x61,0x7A,0x61,0x0A,  /* 00000FF8    "PSTAaza." */
    2.90 +    0x04,0x53,0x4C,0x54,0x5F,0x7B,0x61,0x0A,  /* 00001000    ".SLT_{a." */
    2.91 +    0x0F,0x45,0x56,0x54,0x5F,0x70,0x53,0x4C,  /* 00001008    ".EVT_pSL" */
    2.92 +    0x54,0x5F,0x44,0x50,0x54,0x31,0x70,0x45,  /* 00001010    "T_DPT1pE" */
    2.93 +    0x56,0x54,0x5F,0x44,0x50,0x54,0x32,0xA0,  /* 00001018    "VT_DPT2." */
    2.94 +    0x1B,0x93,0x53,0x4C,0x54,0x5F,0x01,0x86,  /* 00001020    "..SLT_.." */
    2.95 +    0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,  /* 00001028    "\/._SB_P" */
    2.96 +    0x43,0x49,0x30,0x53,0x31,0x46,0x30,0x45,  /* 00001030    "CI0S1F0E" */
    2.97 +    0x56,0x54,0x5F,0xA1,0x1E,0xA0,0x1C,0x93,  /* 00001038    "VT_....." */
    2.98 +    0x53,0x4C,0x54,0x5F,0x0A,0x02,0x86,0x5C,  /* 00001040    "SLT_...\" */
    2.99 +    0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,  /* 00001048    "/._SB_PC" */
   2.100 +    0x49,0x30,0x53,0x32,0x46,0x30,0x45,0x56,  /* 00001050    "I0S2F0EV" */
   2.101 +    0x54,0x5F,
   2.102  };
   2.103  int DsdtLen=sizeof(AmlCode);
     3.1 --- a/tools/firmware/hvmloader/acpi/static_tables.c	Fri Feb 15 12:50:55 2008 +0000
     3.2 +++ b/tools/firmware/hvmloader/acpi/static_tables.c	Fri Feb 15 14:13:17 2008 +0000
     3.3 @@ -59,9 +59,11 @@ struct acpi_20_fadt Fadt = {
     3.4      .pm1a_evt_blk = ACPI_PM1A_EVT_BLK_ADDRESS,
     3.5      .pm1a_cnt_blk = ACPI_PM1A_CNT_BLK_ADDRESS,
     3.6      .pm_tmr_blk = ACPI_PM_TMR_BLK_ADDRESS,
     3.7 +    .gpe0_blk = ACPI_GPE0_BLK_ADDRESS,
     3.8      .pm1_evt_len = ACPI_PM1A_EVT_BLK_BIT_WIDTH / 8,
     3.9      .pm1_cnt_len = ACPI_PM1A_CNT_BLK_BIT_WIDTH / 8,
    3.10      .pm_tmr_len = ACPI_PM_TMR_BLK_BIT_WIDTH / 8,
    3.11 +    .gpe0_blk_len = ACPI_GPE0_BLK_LEN,
    3.12  
    3.13      .p_lvl2_lat = 0x0fff, /* >100,  means we do not support C2 state */
    3.14      .p_lvl3_lat = 0x0fff, /* >1000, means we do not support C3 state */
     4.1 --- a/tools/ioemu/hw/pass-through.c	Fri Feb 15 12:50:55 2008 +0000
     4.2 +++ b/tools/ioemu/hw/pass-through.c	Fri Feb 15 14:13:17 2008 +0000
     4.3 @@ -29,33 +29,161 @@
     4.4  
     4.5  extern FILE *logfile;
     4.6  
     4.7 +struct php_dev {
     4.8 +    struct pt_dev *pt_dev;
     4.9 +    uint8_t valid;
    4.10 +    uint8_t r_bus;
    4.11 +    uint8_t r_dev;
    4.12 +    uint8_t r_func;
    4.13 +};
    4.14 +struct dpci_infos {
    4.15 +
    4.16 +    struct php_dev php_devs[PHP_SLOT_LEN];
    4.17 +
    4.18 +    PCIBus *e_bus;
    4.19 +    struct pci_access *pci_access;
    4.20 +
    4.21 +} dpci_infos;
    4.22 +
    4.23  static int token_value(char *token)
    4.24  {
    4.25 -    token = strchr(token, 'x') + 1;
    4.26      return strtol(token, NULL, 16);
    4.27  }
    4.28  
    4.29  static int next_bdf(char **str, int *seg, int *bus, int *dev, int *func)
    4.30  {
    4.31 -    char *token;
    4.32 +    char *token, *delim = ":.-";
    4.33  
    4.34 -    if ( !(*str) || !strchr(*str, ',') )
    4.35 +    if ( !(*str) ||
    4.36 +          ( !strchr(*str, ':') && !strchr(*str, '.')) )
    4.37          return 0;
    4.38  
    4.39 -    token = *str;
    4.40 -    *seg  = token_value(token);
    4.41 -    token = strchr(token, ',') + 1;
    4.42 +    token  = strsep(str, delim);
    4.43 +    *seg = token_value(token);
    4.44 +
    4.45 +    token  = strsep(str, delim);
    4.46      *bus  = token_value(token);
    4.47 -    token = strchr(token, ',') + 1;
    4.48 +
    4.49 +    token  = strsep(str, delim);
    4.50      *dev  = token_value(token);
    4.51 -    token = strchr(token, ',') + 1;
    4.52 +
    4.53 +    token  = strsep(str, delim);
    4.54      *func  = token_value(token);
    4.55 -    token = strchr(token, ',');
    4.56 -    *str = token ? token + 1 : NULL;
    4.57  
    4.58      return 1;
    4.59  }
    4.60  
    4.61 +/* Insert a new pass-through device into a specific pci slot.
    4.62 + * input  dom:bus:dev.func@slot, chose free one if slot == 0
    4.63 + * return -1: required slot not available
    4.64 + *         0: no free hotplug slots, but normal slot should okay
    4.65 + *        >0: the new hotplug slot
    4.66 + */
    4.67 +static int __insert_to_pci_slot(int bus, int dev, int func, int slot)
    4.68 +{
    4.69 +    int i, php_slot;
    4.70 +
    4.71 +    /* preferred virt pci slot */
    4.72 +    if ( slot >= PHP_SLOT_START && slot < PHP_SLOT_END )
    4.73 +    {
    4.74 +        php_slot = PCI_TO_PHP_SLOT(slot);
    4.75 +        if ( !dpci_infos.php_devs[php_slot].valid )
    4.76 +        {
    4.77 +            goto found;
    4.78 +        }
    4.79 +        else
    4.80 +            return -1;
    4.81 +    }
    4.82 +
    4.83 +    if ( slot != 0 )
    4.84 +        return -1;
    4.85 +
    4.86 +    /* slot == 0, pick up a free one */
    4.87 +    for ( i = 0; i < PHP_SLOT_LEN; i++ )
    4.88 +    {
    4.89 +        if ( !dpci_infos.php_devs[i].valid )
    4.90 +        {
    4.91 +            php_slot = i;
    4.92 +            goto found;
    4.93 +        }
    4.94 +    }
    4.95 +
    4.96 +    /* not found */
    4.97 +    return 0;
    4.98 +
    4.99 +found:
   4.100 +    dpci_infos.php_devs[php_slot].valid  = 1;
   4.101 +    dpci_infos.php_devs[php_slot].r_bus  = bus;
   4.102 +    dpci_infos.php_devs[php_slot].r_dev  = dev;
   4.103 +    dpci_infos.php_devs[php_slot].r_func = func;
   4.104 +    return PHP_TO_PCI_SLOT(php_slot);
   4.105 +}
   4.106 +
   4.107 +/* Insert a new pass-through device into a specific pci slot.
   4.108 + * input  dom:bus:dev.func@slot
   4.109 + */
   4.110 +int insert_to_pci_slot(char *bdf_slt)
   4.111 +{
   4.112 +    int seg, bus, dev, func, slot;
   4.113 +    char *bdf_str, *slt_str, *delim="@";
   4.114 +
   4.115 +    bdf_str = strsep(&bdf_slt, delim);
   4.116 +    slt_str = bdf_slt;
   4.117 +    slot = token_value(slt_str);
   4.118 +
   4.119 +    if ( !next_bdf(&bdf_str, &seg, &bus, &dev, &func))
   4.120 +    {
   4.121 +        return -1;
   4.122 +    }
   4.123 +
   4.124 +    return __insert_to_pci_slot(bus, dev, func, slot);
   4.125 +
   4.126 +}
   4.127 +
   4.128 +/* Test if a pci slot has a device
   4.129 + * 1:  present
   4.130 + * 0:  not present
   4.131 + * -1: invalide pci slot input
   4.132 + */
   4.133 +int test_pci_slot(int slot)
   4.134 +{
   4.135 +    int php_slot;
   4.136 +
   4.137 +    if ( slot < PHP_SLOT_START || slot >= PHP_SLOT_END )
   4.138 +        return -1;
   4.139 +
   4.140 +    php_slot = PCI_TO_PHP_SLOT(slot);
   4.141 +    if ( dpci_infos.php_devs[php_slot].valid )
   4.142 +        return 1;
   4.143 +    else
   4.144 +        return 0;
   4.145 +}
   4.146 +
   4.147 +/* find the pci slot for pass-through dev with specified BDF */
   4.148 +int bdf_to_slot(char *bdf_str)
   4.149 +{
   4.150 +    int seg, bus, dev, func, i;
   4.151 +
   4.152 +    if ( !next_bdf(&bdf_str, &seg, &bus, &dev, &func))
   4.153 +    {
   4.154 +        return -1;
   4.155 +    }
   4.156 +
   4.157 +    /* locate the virtual pci slot for this VTd device */
   4.158 +    for ( i = 0; i < PHP_SLOT_LEN; i++ )
   4.159 +    {
   4.160 +        if ( dpci_infos.php_devs[i].valid &&
   4.161 +           dpci_infos.php_devs[i].r_bus == bus &&
   4.162 +           dpci_infos.php_devs[i].r_dev  == dev &&
   4.163 +           dpci_infos.php_devs[i].r_func == func )
   4.164 +        {
   4.165 +            return PHP_TO_PCI_SLOT(i);
   4.166 +        }
   4.167 +    }
   4.168 +
   4.169 +    return -1;
   4.170 +}
   4.171 +
   4.172  /* Being called each time a mmio region has been updated */
   4.173  void pt_iomem_map(PCIDevice *d, int i, uint32_t e_phys, uint32_t e_size,
   4.174                    int type)
   4.175 @@ -269,15 +397,64 @@ static int pt_register_regions(struct pt
   4.176      return 0;
   4.177  }
   4.178  
   4.179 +static int pt_unregister_regions(struct pt_dev *assigned_device)
   4.180 +{
   4.181 +    int i, type, ret;
   4.182 +    uint32_t e_size;
   4.183 +    PCIDevice *d = (PCIDevice*)assigned_device;
   4.184 +
   4.185 +    for ( i = 0; i < PCI_NUM_REGIONS; i++ )
   4.186 +    {
   4.187 +        e_size = assigned_device->bases[i].e_size;
   4.188 +        if ( e_size == 0 )
   4.189 +            continue;
   4.190 +
   4.191 +        type = d->io_regions[i].type;
   4.192 +
   4.193 +        if ( type == PCI_ADDRESS_SPACE_MEM ||
   4.194 +             type == PCI_ADDRESS_SPACE_MEM_PREFETCH )
   4.195 +        {
   4.196 +            ret = xc_domain_memory_mapping(xc_handle, domid,
   4.197 +                    assigned_device->bases[i].e_physbase >> XC_PAGE_SHIFT,
   4.198 +                    assigned_device->bases[i].access.maddr >> XC_PAGE_SHIFT,
   4.199 +                    (e_size+XC_PAGE_SIZE-1) >> XC_PAGE_SHIFT,
   4.200 +                    DPCI_REMOVE_MAPPING);
   4.201 +            if ( ret != 0 )
   4.202 +            {
   4.203 +                PT_LOG("Error: remove old mem mapping failed!\n");
   4.204 +                continue;
   4.205 +            }
   4.206 +
   4.207 +        }
   4.208 +        else if ( type == PCI_ADDRESS_SPACE_IO )
   4.209 +        {
   4.210 +            ret = xc_domain_ioport_mapping(xc_handle, domid,
   4.211 +                        assigned_device->bases[i].e_physbase,
   4.212 +                        assigned_device->bases[i].access.pio_base,
   4.213 +                        e_size,
   4.214 +                        DPCI_REMOVE_MAPPING);
   4.215 +            if ( ret != 0 )
   4.216 +            {
   4.217 +                PT_LOG("Error: remove old io mapping failed!\n");
   4.218 +                continue;
   4.219 +            }
   4.220 +
   4.221 +        }
   4.222 +        
   4.223 +    }
   4.224 +
   4.225 +}
   4.226 +
   4.227  struct pt_dev * register_real_device(PCIBus *e_bus,
   4.228          const char *e_dev_name, int e_devfn, uint8_t r_bus, uint8_t r_dev,
   4.229          uint8_t r_func, uint32_t machine_irq, struct pci_access *pci_access)
   4.230  {
   4.231 -    int rc, i;
   4.232 +    int rc = -1, i;
   4.233      struct pt_dev *assigned_device = NULL;
   4.234      struct pci_dev *pci_dev;
   4.235      uint8_t e_device, e_intx;
   4.236      struct pci_config_cf8 machine_bdf;
   4.237 +    int free_pci_slot = -1;
   4.238  
   4.239      PT_LOG("Assigning real physical device %02x:%02x.%x ...\n",
   4.240          r_bus, r_dev, r_func);
   4.241 @@ -296,6 +473,15 @@ struct pt_dev * register_real_device(PCI
   4.242          return NULL;
   4.243      }
   4.244  
   4.245 +    if ( e_devfn == PT_VIRT_DEVFN_AUTO ) {
   4.246 +        /*indicate a static assignment(not hotplug), so find a free PCI hot plug slot */
   4.247 +        free_pci_slot = __insert_to_pci_slot(r_bus, r_dev, r_func, 0);
   4.248 +        if ( free_pci_slot > 0 )
   4.249 +            e_devfn = free_pci_slot  << 3;
   4.250 +        else
   4.251 +            PT_LOG("Error: no free virtual PCI hot plug slot, thus no live migration.\n");
   4.252 +    }
   4.253 +
   4.254      /* Register device */
   4.255      assigned_device = (struct pt_dev *) pci_register_device(e_bus, e_dev_name,
   4.256                                  sizeof(struct pt_dev), e_devfn,
   4.257 @@ -306,8 +492,12 @@ struct pt_dev * register_real_device(PCI
   4.258          return NULL;
   4.259      }
   4.260  
   4.261 +    if ( free_pci_slot > 0 )
   4.262 +        dpci_infos.php_devs[PCI_TO_PHP_SLOT(free_pci_slot)].pt_dev = assigned_device;
   4.263 +
   4.264      assigned_device->pci_dev = pci_dev;
   4.265  
   4.266 +
   4.267      /* Assign device */
   4.268      machine_bdf.reg = 0;
   4.269      machine_bdf.bus = r_bus;
   4.270 @@ -355,11 +545,96 @@ struct pt_dev * register_real_device(PCI
   4.271      return assigned_device;
   4.272  }
   4.273  
   4.274 +int unregister_real_device(int php_slot)
   4.275 +{
   4.276 +    struct php_dev *php_dev;
   4.277 +    struct pci_dev *pci_dev;
   4.278 +    uint8_t e_device, e_intx;
   4.279 +    struct pt_dev *assigned_device = NULL;
   4.280 +    uint32_t machine_irq;
   4.281 +    uint32_t bdf = 0;
   4.282 +    int rc = -1;
   4.283 +
   4.284 +    if ( php_slot < 0 || php_slot >= PHP_SLOT_LEN )
   4.285 +       return -1;
   4.286 +
   4.287 +    php_dev = &dpci_infos.php_devs[php_slot];
   4.288 +    assigned_device = php_dev->pt_dev;
   4.289 +
   4.290 +    if ( !assigned_device || !php_dev->valid )
   4.291 +        return -1;
   4.292 +
   4.293 +    pci_dev = assigned_device->pci_dev;
   4.294 +
   4.295 +    /* hide pci dev from qemu */
   4.296 +    pci_hide_device((PCIDevice*)assigned_device);
   4.297 +
   4.298 +    /* Unbind interrupt */
   4.299 +    e_device = (assigned_device->dev.devfn >> 3) & 0x1f;
   4.300 +    e_intx = assigned_device->dev.config[0x3d]-1;
   4.301 +    machine_irq = pci_dev->irq;
   4.302 +
   4.303 +    if ( machine_irq != 0 ) {
   4.304 +        rc = xc_domain_unbind_pt_irq(xc_handle, domid, machine_irq, PT_IRQ_TYPE_PCI, 0,
   4.305 +                                       e_device, e_intx, 0);
   4.306 +        if ( rc < 0 )
   4.307 +        {
   4.308 +            /* TBD: unregister device in case of an error */
   4.309 +            PT_LOG("Error: Unbinding of interrupt failed! rc=%d\n", rc);
   4.310 +        }
   4.311 +    }
   4.312 +
   4.313 +    /* unregister real device's MMIO/PIO BARs */
   4.314 +    pt_unregister_regions(assigned_device);
   4.315 +    
   4.316 +    /* deassign the dev to dom0 */
   4.317 +    bdf |= (pci_dev->bus  & 0xff) << 16;
   4.318 +    bdf |= (pci_dev->dev  & 0x1f) << 11;
   4.319 +    bdf |= (pci_dev->func & 0x1f) << 8;
   4.320 +    if ( (rc = xc_deassign_device(xc_handle, domid, bdf)) != 0)
   4.321 +        PT_LOG("Error: Revoking the device failed! rc=%d\n", rc);
   4.322 +
   4.323 +    /* mark this slot as free */
   4.324 +    php_dev->valid = 0;
   4.325 +    php_dev->pt_dev = NULL;
   4.326 +    qemu_free(assigned_device);
   4.327 +
   4.328 +    return 0;
   4.329 +}
   4.330 +
   4.331 +int power_on_php_slot(int php_slot)
   4.332 +{
   4.333 +    struct php_dev *php_dev = &dpci_infos.php_devs[php_slot];
   4.334 +    int pci_slot = php_slot + PHP_SLOT_START;
   4.335 +    struct pt_dev *pt_dev;
   4.336 +    pt_dev = 
   4.337 +        register_real_device(dpci_infos.e_bus,
   4.338 +            "DIRECT PCI",
   4.339 +            pci_slot << 3,
   4.340 +            php_dev->r_bus,
   4.341 +            php_dev->r_dev,
   4.342 +            php_dev->r_func,
   4.343 +            PT_MACHINE_IRQ_AUTO,
   4.344 +            dpci_infos.pci_access);
   4.345 +
   4.346 +    php_dev->pt_dev = pt_dev;
   4.347 +
   4.348 +    return 0;
   4.349 +
   4.350 +}
   4.351 +
   4.352 +int power_off_php_slot(int php_slot)
   4.353 +{
   4.354 +    return unregister_real_device(php_slot);
   4.355 +}
   4.356 +
   4.357  int pt_init(PCIBus *e_bus, char *direct_pci)
   4.358  {
   4.359 -    int seg, b, d, f;
   4.360 +    int seg, b, d, f, php_slot = 0;
   4.361      struct pt_dev *pt_dev;
   4.362      struct pci_access *pci_access;
   4.363 +    char *vslots;
   4.364 +    char slot_str[8];
   4.365  
   4.366      /* Initialize libpci */
   4.367      pci_access = pci_alloc();
   4.368 @@ -371,6 +646,19 @@ int pt_init(PCIBus *e_bus, char *direct_
   4.369      pci_init(pci_access);
   4.370      pci_scan_bus(pci_access);
   4.371  
   4.372 +    memset(&dpci_infos, 0, sizeof(struct dpci_infos));
   4.373 +    dpci_infos.pci_access = pci_access;
   4.374 +    dpci_infos.e_bus      = e_bus;
   4.375 +
   4.376 +    if ( strlen(direct_pci) == 0 ) {
   4.377 +        return 0;
   4.378 +    }
   4.379 +
   4.380 +    /* the virtual pci slots of all pass-through devs
   4.381 +     * with hex format: xx;xx...;
   4.382 +     */
   4.383 +    vslots = qemu_mallocz ( strlen(direct_pci) / 3 );
   4.384 +
   4.385      /* Assign given devices to guest */
   4.386      while ( next_bdf(&direct_pci, &seg, &b, &d, &f) )
   4.387      {
   4.388 @@ -382,8 +670,37 @@ int pt_init(PCIBus *e_bus, char *direct_
   4.389              PT_LOG("Error: Registration failed (%02x:%02x.%x)\n", b, d, f);
   4.390              return -1;
   4.391          }
   4.392 +
   4.393 +        /* Record the virtual slot info */
   4.394 +        if ( php_slot < PHP_SLOT_LEN &&
   4.395 +              dpci_infos.php_devs[php_slot].pt_dev == pt_dev )
   4.396 +        {
   4.397 +            sprintf(slot_str, "0x%x;", PHP_TO_PCI_SLOT(php_slot));
   4.398 +        }
   4.399 +        else
   4.400 +            sprintf(slot_str, "0x%x;", 0);
   4.401 +
   4.402 +        strcat(vslots, slot_str);
   4.403 +        php_slot++;
   4.404      }
   4.405  
   4.406 +    /* Write virtual slots info to xenstore for Control panel use */
   4.407 +    xenstore_write_vslots(vslots);
   4.408 +
   4.409 +    qemu_free(vslots);
   4.410 +
   4.411      /* Success */
   4.412      return 0;
   4.413  }
   4.414 +
   4.415 +void pt_uninit(void)
   4.416 +{
   4.417 +    struct pci_access *access;
   4.418 +
   4.419 +    /* clean up the libpci */
   4.420 +    access = dpci_infos.pci_access;
   4.421 +    if ( access ) {
   4.422 +        pci_cleanup(access);
   4.423 +    }
   4.424 +
   4.425 +}
     5.1 --- a/tools/ioemu/hw/pc.c	Fri Feb 15 12:50:55 2008 +0000
     5.2 +++ b/tools/ioemu/hw/pc.c	Fri Feb 15 14:13:17 2008 +0000
     5.3 @@ -945,8 +945,10 @@ static void pc_init1(uint64_t ram_size, 
     5.4      }
     5.5  
     5.6  #ifdef CONFIG_PASSTHROUGH
     5.7 -    /* Pass-through Initialization */
     5.8 -    if ( pci_enabled && direct_pci )
     5.9 +    /* Pass-through Initialization
    5.10 +     * init libpci even direct_pci is null, as can hotplug a dev runtime
    5.11 +     */
    5.12 +    if ( pci_enabled )
    5.13      {
    5.14          rc = pt_init(pci_bus, direct_pci); 
    5.15          if ( rc < 0 )
     6.1 --- a/tools/ioemu/hw/pci.c	Fri Feb 15 12:50:55 2008 +0000
     6.2 +++ b/tools/ioemu/hw/pci.c	Fri Feb 15 14:13:17 2008 +0000
     6.3 @@ -107,7 +107,8 @@ PCIDevice *pci_register_device(PCIBus *b
     6.4      
     6.5      if (devfn < 0) {
     6.6          for(devfn = bus->devfn_min ; devfn < 256; devfn += 8) {
     6.7 -            if (!bus->devices[devfn])
     6.8 +            if ( !bus->devices[devfn] &&
     6.9 +                 !( devfn >= PHP_DEVFN_START && devfn < PHP_DEVFN_END ) )
    6.10                  goto found;
    6.11          }
    6.12          return NULL;
    6.13 @@ -132,6 +133,12 @@ PCIDevice *pci_register_device(PCIBus *b
    6.14      return pci_dev;
    6.15  }
    6.16  
    6.17 +void pci_hide_device(PCIDevice *pci_dev)
    6.18 +{
    6.19 +    PCIBus *bus = pci_dev->bus;
    6.20 +    bus->devices[pci_dev->devfn] = NULL;
    6.21 +}
    6.22 +
    6.23  void pci_register_io_region(PCIDevice *pci_dev, int region_num, 
    6.24                              uint32_t size, int type, 
    6.25                              PCIMapIORegionFunc *map_func)
     7.1 --- a/tools/ioemu/hw/piix4acpi.c	Fri Feb 15 12:50:55 2008 +0000
     7.2 +++ b/tools/ioemu/hw/piix4acpi.c	Fri Feb 15 14:13:17 2008 +0000
     7.3 @@ -24,6 +24,7 @@
     7.4   */
     7.5  
     7.6  #include "vl.h"
     7.7 +#include <xen/hvm/ioreq.h>
     7.8  
     7.9  /* PM1a_CNT bits, as defined in the ACPI specification. */
    7.10  #define SCI_EN            (1 <<  0)
    7.11 @@ -36,6 +37,19 @@
    7.12  #define SLP_TYP_S4        (6 << 10)
    7.13  #define SLP_TYP_S5        (7 << 10)
    7.14  
    7.15 +#define ACPI_DBG_IO_ADDR  0xb044
    7.16 +#define ACPI_PHP_IO_ADDR  0x10c0
    7.17 +
    7.18 +#define PHP_EVT_ADD     0x0
    7.19 +#define PHP_EVT_REMOVE  0x3
    7.20 +
    7.21 +#define ACPI_SCI_IRQ 9
    7.22 +
    7.23 +/* The bit in GPE0_STS/EN to notify the pci hotplug event */
    7.24 +#define ACPI_PHP_GPE_BIT 3
    7.25 +
    7.26 +#define ACPI_PHP_SLOT_NUM PHP_SLOT_LEN
    7.27 +
    7.28  typedef struct AcpiDeviceState AcpiDeviceState;
    7.29  AcpiDeviceState *acpi_device_table;
    7.30  
    7.31 @@ -44,6 +58,27 @@ typedef struct PCIAcpiState {
    7.32      uint16_t pm1_control; /* pm1a_ECNT_BLK */
    7.33  } PCIAcpiState;
    7.34  
    7.35 +typedef struct GPEState {
    7.36 +    /* GPE0 block */
    7.37 +    uint8_t gpe0_sts[ACPI_GPE0_BLK_LEN / 2];
    7.38 +    uint8_t gpe0_en[ACPI_GPE0_BLK_LEN / 2];
    7.39 +
    7.40 +    /* SCI IRQ level */
    7.41 +    uint8_t sci_asserted;
    7.42 +
    7.43 +} GPEState;
    7.44 +
    7.45 +GPEState gpe_state;
    7.46 +
    7.47 +typedef struct PHPSlots {
    7.48 +    struct {
    7.49 +        uint8_t status;    /* Apaptor stats */
    7.50 +    } slot[ACPI_PHP_SLOT_NUM];
    7.51 +    uint8_t plug_evt;      /* slot|event slot:0-no event;1-1st. event:0-remove;1-add */
    7.52 +} PHPSlots;
    7.53 +
    7.54 +PHPSlots php_slots;
    7.55 +
    7.56  static void piix4acpi_save(QEMUFile *f, void *opaque)
    7.57  {
    7.58      PCIAcpiState *s = opaque;
    7.59 @@ -142,6 +177,318 @@ static void acpi_map(PCIDevice *pci_dev,
    7.60      register_ioport_read(addr + 4, 2, 2, acpiPm1Control_readw, d);
    7.61  }
    7.62  
    7.63 +static inline int test_bit(uint8_t *map, int bit)
    7.64 +{
    7.65 +    return ( map[bit / 8] & (1 << (bit % 8)) );
    7.66 +}
    7.67 +
    7.68 +static inline void set_bit(uint8_t *map, int bit)
    7.69 +{
    7.70 +    map[bit / 8] |= (1 << (bit % 8));
    7.71 +}
    7.72 +
    7.73 +static inline void clear_bit(uint8_t *map, int bit)
    7.74 +{
    7.75 +    map[bit / 8] &= ~(1 << (bit % 8));
    7.76 +}
    7.77 +
    7.78 +extern FILE *logfile;
    7.79 +static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val)
    7.80 +{
    7.81 +#if defined(DEBUG)
    7.82 +    printf("ACPI: DBG: 0x%08x\n", val);
    7.83 +#endif
    7.84 +    fprintf(logfile, "ACPI:debug: write addr=0x%x, val=0x%x.\n", addr, val);
    7.85 +}
    7.86 +
    7.87 +/*
    7.88 + * simple PCI hotplug controller IO 
    7.89 + * ACPI_PHP_IO_ADDR + :
    7.90 + * 0 - the hotplug description: slot(|event(remove/add); 
    7.91 + * 1 - 1st php slot ctr/sts reg
    7.92 + * 2 - 2nd php slot ctr/sts reg
    7.93 + * ......
    7.94 + */
    7.95 +static uint32_t acpi_php_readb(void *opaque, uint32_t addr)
    7.96 +{
    7.97 +    PHPSlots *hotplug_slots = opaque;
    7.98 +    int num;
    7.99 +    uint32_t val; 
   7.100 +
   7.101 +    switch (addr)
   7.102 +    {
   7.103 +        case ACPI_PHP_IO_ADDR:
   7.104 +            val = hotplug_slots->plug_evt;
   7.105 +            break;
   7.106 +        default:
   7.107 +            num = addr - ACPI_PHP_IO_ADDR - 1;
   7.108 +            val = hotplug_slots->slot[num].status;
   7.109 +    }
   7.110 +
   7.111 +    fprintf(logfile, "ACPI PCI hotplug: read addr=0x%x, val=0x%x.\n", addr, val);
   7.112 +    return val;
   7.113 +}
   7.114 +
   7.115 +static void acpi_php_writeb(void *opaque, uint32_t addr, uint32_t val)
   7.116 +{
   7.117 +    PHPSlots *hotplug_slots = opaque;
   7.118 +    int php_slot;
   7.119 +    fprintf(logfile, "ACPI PCI hotplug: write addr=0x%x, val=0x%x.\n", addr, val);
   7.120 +
   7.121 +    switch (addr)
   7.122 +    {
   7.123 +        case ACPI_PHP_IO_ADDR:
   7.124 +            break;
   7.125 +        default:
   7.126 +            php_slot = addr - ACPI_PHP_IO_ADDR - 1;
   7.127 +            if ( val == 0x1 ) { /* Eject command */
   7.128 +                /* make _STA of the slot 0 */
   7.129 +                hotplug_slots->slot[php_slot].status = 0;
   7.130 +
   7.131 +                /* clear the hotplug event */
   7.132 +                hotplug_slots->plug_evt = 0;
   7.133 +
   7.134 +                /* power off the slot */
   7.135 +                power_off_php_slot(php_slot);
   7.136 +
   7.137 +                /* signal the CP ACPI hot remove done. */
   7.138 +                xenstore_record_dm_state("pci-removed");
   7.139 +            }
   7.140 +    }
   7.141 +}
   7.142 +
   7.143 +static void pcislots_save(QEMUFile* f, void* opaque)
   7.144 +{
   7.145 +    PHPSlots *s = (PHPSlots*)opaque;
   7.146 +    int i;
   7.147 +    for ( i = 0; i < ACPI_PHP_SLOT_NUM; i++ ) {
   7.148 +        qemu_put_8s( f, &s->slot[i].status);
   7.149 +    }
   7.150 +    qemu_put_8s(f, &s->plug_evt);
   7.151 +}
   7.152 +
   7.153 +static int pcislots_load(QEMUFile* f, void* opaque, int version_id)
   7.154 +{
   7.155 +    PHPSlots *s = (PHPSlots*)opaque;
   7.156 +    int i;
   7.157 +    if (version_id != 1)
   7.158 +        return -EINVAL;
   7.159 +    for ( i = 0; i < ACPI_PHP_SLOT_NUM; i++ ) {
   7.160 +        qemu_get_8s( f, &s->slot[i].status);
   7.161 +    }
   7.162 +    qemu_get_8s(f, &s->plug_evt);
   7.163 +    return 0;
   7.164 +}
   7.165 +
   7.166 +static void php_slots_init(void)
   7.167 +{
   7.168 +    PHPSlots *slots = &php_slots;
   7.169 +    int i;
   7.170 +    memset(slots, 0, sizeof(PHPSlots));
   7.171 +
   7.172 +    /* update the pci slot status */
   7.173 +    for ( i = 0; i < PHP_SLOT_LEN; i++ ) {
   7.174 +        if ( test_pci_slot( PHP_TO_PCI_SLOT(i) ) == 1 )
   7.175 +            slots->slot[i].status = 0xf;
   7.176 +    }
   7.177 +
   7.178 +
   7.179 +    /* ACPI PCI hotplug controller */
   7.180 +    register_ioport_read(ACPI_PHP_IO_ADDR, ACPI_PHP_SLOT_NUM + 1, 1, acpi_php_readb, slots);
   7.181 +    register_ioport_write(ACPI_PHP_IO_ADDR, ACPI_PHP_SLOT_NUM + 1, 1, acpi_php_writeb, slots);
   7.182 +    register_savevm("pcislots", 0, 1, pcislots_save, pcislots_load, slots);
   7.183 +}
   7.184 +
   7.185 +/* GPEx_STS occupy 1st half of the block, while GPEx_EN 2nd half */
   7.186 +static uint32_t gpe_sts_read(void *opaque, uint32_t addr)
   7.187 +{
   7.188 +    GPEState *s = opaque;
   7.189 +
   7.190 +    return s->gpe0_sts[addr - ACPI_GPE0_BLK_ADDRESS];
   7.191 +}
   7.192 +
   7.193 +/* write 1 to clear specific GPE bits */
   7.194 +static void gpe_sts_write(void *opaque, uint32_t addr, uint32_t val)
   7.195 +{
   7.196 +    GPEState *s = opaque;
   7.197 +    int hotplugged = 0;
   7.198 +
   7.199 +    fprintf(logfile, "gpe_sts_write: addr=0x%x, val=0x%x.\n", addr, val);
   7.200 +
   7.201 +    hotplugged = test_bit(&s->gpe0_sts[0], ACPI_PHP_GPE_BIT);
   7.202 +    s->gpe0_sts[addr - ACPI_GPE0_BLK_ADDRESS] &= ~val;
   7.203 +    if ( s->sci_asserted &&
   7.204 +         hotplugged &&
   7.205 +         !test_bit(&s->gpe0_sts[0], ACPI_PHP_GPE_BIT)) {
   7.206 +        fprintf(logfile, "Clear the GPE0_STS bit for ACPI hotplug & deassert the IRQ.\n");
   7.207 +        pic_set_irq(ACPI_SCI_IRQ, 0);
   7.208 +    }
   7.209 +
   7.210 +}
   7.211 +
   7.212 +static uint32_t gpe_en_read(void *opaque, uint32_t addr)
   7.213 +{
   7.214 +    GPEState *s = opaque;
   7.215 +
   7.216 +    return s->gpe0_en[addr - (ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2)];
   7.217 +}
   7.218 +
   7.219 +/* write 0 to clear en bit */
   7.220 +static void gpe_en_write(void *opaque, uint32_t addr, uint32_t val)
   7.221 +{
   7.222 +    GPEState *s = opaque;
   7.223 +    int reg_count;
   7.224 +
   7.225 +    fprintf(logfile, "gpe_en_write: addr=0x%x, val=0x%x.\n", addr, val);
   7.226 +    reg_count = addr - (ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2);
   7.227 +    s->gpe0_en[reg_count] = val;
   7.228 +    /* If disable GPE bit right after generating SCI on it, 
   7.229 +     * need deassert the intr to avoid redundant intrs
   7.230 +     */
   7.231 +    if ( s->sci_asserted &&
   7.232 +            reg_count == (ACPI_PHP_GPE_BIT / 8) &&
   7.233 +            !(val & (1 << (ACPI_PHP_GPE_BIT % 8))) ) {
   7.234 +        fprintf(logfile, "deassert due to disable GPE bit.\n");
   7.235 +        s->sci_asserted = 0;
   7.236 +        pic_set_irq(ACPI_SCI_IRQ, 0);
   7.237 +    }
   7.238 +
   7.239 +}
   7.240 +
   7.241 +static void gpe_save(QEMUFile* f, void* opaque)
   7.242 +{
   7.243 +    GPEState *s = (GPEState*)opaque;
   7.244 +    int i;
   7.245 +
   7.246 +    for ( i = 0; i < ACPI_GPE0_BLK_LEN / 2; i++ ) {
   7.247 +        qemu_put_8s(f, &s->gpe0_sts[i]);
   7.248 +        qemu_put_8s(f, &s->gpe0_en[i]);
   7.249 +    }
   7.250 +
   7.251 +    qemu_put_8s(f, &s->sci_asserted);
   7.252 +    if ( s->sci_asserted ) {
   7.253 +        fprintf(logfile, "gpe_save with sci asserted!\n");
   7.254 +    }
   7.255 +}
   7.256 +
   7.257 +static int gpe_load(QEMUFile* f, void* opaque, int version_id)
   7.258 +{
   7.259 +    GPEState *s = (GPEState*)opaque;
   7.260 +    int i;
   7.261 +    if (version_id != 1)
   7.262 +        return -EINVAL;
   7.263 +
   7.264 +    for ( i = 0; i < ACPI_GPE0_BLK_LEN / 2; i++ ) {
   7.265 +        qemu_get_8s(f, &s->gpe0_sts[i]);
   7.266 +        qemu_get_8s(f, &s->gpe0_en[i]);
   7.267 +    }
   7.268 +
   7.269 +    qemu_get_8s(f, &s->sci_asserted);
   7.270 +    return 0;
   7.271 +}
   7.272 +
   7.273 +static void gpe_acpi_init(void)
   7.274 +{
   7.275 +    GPEState *s = &gpe_state;
   7.276 +    memset(s, 0, sizeof(GPEState));
   7.277 +
   7.278 +    register_ioport_read(ACPI_GPE0_BLK_ADDRESS,
   7.279 +            ACPI_GPE0_BLK_LEN / 2,
   7.280 +            1,
   7.281 +            gpe_sts_read,
   7.282 +            s);
   7.283 +    register_ioport_read(ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2,
   7.284 +            ACPI_GPE0_BLK_LEN / 2,
   7.285 +            1,
   7.286 +            gpe_en_read,
   7.287 +            s);
   7.288 +
   7.289 +    register_ioport_write(ACPI_GPE0_BLK_ADDRESS,
   7.290 +            ACPI_GPE0_BLK_LEN / 2,
   7.291 +            1,
   7.292 +            gpe_sts_write,
   7.293 +            s);
   7.294 +    register_ioport_write(ACPI_GPE0_BLK_ADDRESS + ACPI_GPE0_BLK_LEN / 2,
   7.295 +            ACPI_GPE0_BLK_LEN / 2,
   7.296 +            1,
   7.297 +            gpe_en_write,
   7.298 +            s);
   7.299 +
   7.300 +    register_savevm("gpe", 0, 1, gpe_save, gpe_load, s);
   7.301 +}
   7.302 +
   7.303 +static void acpi_sci_intr(GPEState *s)
   7.304 +{
   7.305 +    if ( !test_bit(&s->gpe0_sts[0], ACPI_PHP_GPE_BIT) &&
   7.306 +            test_bit(&s->gpe0_en[0], ACPI_PHP_GPE_BIT) ) {
   7.307 +
   7.308 +        set_bit(&s->gpe0_sts[0], ACPI_PHP_GPE_BIT);
   7.309 +        s->sci_asserted = 1;
   7.310 +        pic_set_irq(ACPI_SCI_IRQ, 1);
   7.311 +        fprintf(logfile, "generate a sci for PHP.\n");
   7.312 +    }
   7.313 +}
   7.314 +
   7.315 +void acpi_php_del(int pci_slot)
   7.316 +{
   7.317 +    GPEState *s = &gpe_state;
   7.318 +    PHPSlots *hotplug_slots = &php_slots;
   7.319 +    int php_slot = PCI_TO_PHP_SLOT(pci_slot);
   7.320 +
   7.321 +    if ( pci_slot < PHP_SLOT_START || pci_slot >= PHP_SLOT_END ) {
   7.322 +        fprintf(logfile, "not find the pci slot %d when hot remove.\n", pci_slot);
   7.323 +
   7.324 +        return;
   7.325 +    }
   7.326 +
   7.327 +    /* update the php controller status */
   7.328 +    hotplug_slots->plug_evt = (((php_slot+1) << 4) | PHP_EVT_REMOVE);
   7.329 +
   7.330 +    /* generate a SCI interrupt */
   7.331 +    acpi_sci_intr(s);
   7.332 +}
   7.333 +
   7.334 +void acpi_php_add(int pci_slot)
   7.335 +{
   7.336 +    GPEState *s = &gpe_state;
   7.337 +    PHPSlots *hotplug_slots = &php_slots;
   7.338 +    int php_slot = PCI_TO_PHP_SLOT(pci_slot);
   7.339 +    char ret_str[30];
   7.340 +
   7.341 +    if ( pci_slot < PHP_SLOT_START || pci_slot >= PHP_SLOT_END ) {
   7.342 +        fprintf(logfile, "hot add pci slot %d exceed.\n", pci_slot);
   7.343 +
   7.344 +        if ( pci_slot == 0 )
   7.345 +            sprintf(ret_str, "no free hotplug slots");
   7.346 +        else if ( pci_slot == -1 )
   7.347 +            sprintf(ret_str, "wrong bdf or vslot");
   7.348 +
   7.349 +        if ( strlen(ret_str) > 0 )
   7.350 +            xenstore_record_dm("parameter", ret_str);
   7.351 +
   7.352 +        return;
   7.353 +    }
   7.354 +
   7.355 +    /* update the php controller status */
   7.356 +    hotplug_slots->plug_evt = (((php_slot+1) << 4) | PHP_EVT_ADD);
   7.357 +
   7.358 +    /* update the slot status as present */
   7.359 +    hotplug_slots->slot[php_slot].status = 0xf;
   7.360 +
   7.361 +    /* power on the slot */
   7.362 +    power_on_php_slot(php_slot);
   7.363 +
   7.364 +    /* tell Control panel which slot for the new pass-throgh dev */
   7.365 +    sprintf(ret_str, "0x%x", pci_slot);
   7.366 +    xenstore_record_dm("parameter", ret_str);
   7.367 +
   7.368 +    /* signal the CP ACPI hot insert done */
   7.369 +    xenstore_record_dm_state("pci-inserted");
   7.370 +
   7.371 +    /* generate a SCI interrupt */
   7.372 +    acpi_sci_intr(s);
   7.373 +}
   7.374 +
   7.375  /* PIIX4 acpi pci configuration space, func 2 */
   7.376  void pci_piix4_acpi_init(PCIBus *bus, int devfn)
   7.377  {
   7.378 @@ -181,5 +528,12 @@ void pci_piix4_acpi_init(PCIBus *bus, in
   7.379  
   7.380      acpi_map((PCIDevice *)d, 0, 0x1f40, 0x10, PCI_ADDRESS_SPACE_IO);
   7.381  
   7.382 +    gpe_acpi_init();
   7.383 +
   7.384 +    php_slots_init();
   7.385 +
   7.386 +    /* for ACPI debug */
   7.387 +    register_ioport_write(ACPI_DBG_IO_ADDR, 4, 4, acpi_dbg_writel, d);
   7.388 +
   7.389      register_savevm("piix4acpi", 0, 1, piix4acpi_save, piix4acpi_load, d);
   7.390  }
     8.1 --- a/tools/ioemu/monitor.c	Fri Feb 15 12:50:55 2008 +0000
     8.2 +++ b/tools/ioemu/monitor.c	Fri Feb 15 14:13:17 2008 +0000
     8.3 @@ -1280,6 +1280,12 @@ static term_cmd_t term_cmds[] = {
     8.4        "device", "add USB device (e.g. 'host:bus.addr' or 'host:vendor_id:product_id')" },
     8.5      { "usb_del", "s", do_usb_del,
     8.6        "device", "remove USB device 'bus.addr'" },
     8.7 +#ifdef CONFIG_PHP_DEBUG
     8.8 +    { "pci_add", "s", do_pci_add,
     8.9 +      "device", "insert PCI pass-through device by BDF,e.g. (dom, bus, dev, func) by hex '0x0, 0x3, 0x0, 0x0'" },
    8.10 +    { "pci_del", "s", do_pci_del,
    8.11 +      "device", "remove PCI pass-through device by BDF,e.g. (dom, bus, dev, func) by hex '0x0, 0x3, 0x0, 0x0'" },
    8.12 +#endif
    8.13  #ifndef CONFIG_DM
    8.14      { "cpu", "i", do_cpu_set, 
    8.15        "index", "set the default CPU" },
     9.1 --- a/tools/ioemu/vl.c	Fri Feb 15 12:50:55 2008 +0000
     9.2 +++ b/tools/ioemu/vl.c	Fri Feb 15 14:13:17 2008 +0000
     9.3 @@ -4382,6 +4382,24 @@ void usb_info(void)
     9.4      }
     9.5  }
     9.6  
     9.7 +void do_pci_del(char *devname)
     9.8 +{
     9.9 +    int pci_slot;
    9.10 +    pci_slot = bdf_to_slot(devname);
    9.11 +
    9.12 +    acpi_php_del(pci_slot);
    9.13 +}
    9.14 +
    9.15 +void do_pci_add(char *devname)
    9.16 +{
    9.17 +    int pci_slot;
    9.18 +
    9.19 +    pci_slot = insert_to_pci_slot(devname);
    9.20 +
    9.21 +    acpi_php_add(pci_slot);
    9.22 +}
    9.23 +
    9.24 +
    9.25  /***********************************************************/
    9.26  /* pid file */
    9.27  
    9.28 @@ -7067,7 +7085,7 @@ int main(int argc, char **argv)
    9.29  #endif
    9.30      sigset_t set;
    9.31      char qemu_dm_logfilename[128];
    9.32 -    const char *direct_pci = NULL;
    9.33 +    const char *direct_pci = direct_pci_str;
    9.34  
    9.35  #if !defined(__sun__) && !defined(CONFIG_STUBDOM)
    9.36      /* Maximise rlimits. Needed where default constraints are tight (*BSD). */
    9.37 @@ -7590,9 +7608,6 @@ int main(int argc, char **argv)
    9.38              case QEMU_OPTION_vncunused:
    9.39                  vncunused++;
    9.40                  break;
    9.41 -            case QEMU_OPTION_pci:
    9.42 -                direct_pci = optarg;
    9.43 -                break;
    9.44              }
    9.45          }
    9.46      }
    9.47 @@ -7970,5 +7985,6 @@ int main(int argc, char **argv)
    9.48  
    9.49      main_loop();
    9.50      quit_timers();
    9.51 +    pt_uninit();
    9.52      return 0;
    9.53  }
    10.1 --- a/tools/ioemu/vl.h	Fri Feb 15 12:50:55 2008 +0000
    10.2 +++ b/tools/ioemu/vl.h	Fri Feb 15 14:13:17 2008 +0000
    10.3 @@ -817,11 +817,15 @@ struct PCIDevice {
    10.4      int irq_state[4];
    10.5  };
    10.6  
    10.7 +extern char direct_pci_str[];
    10.8 +
    10.9  PCIDevice *pci_register_device(PCIBus *bus, const char *name,
   10.10                                 int instance_size, int devfn,
   10.11                                 PCIConfigReadFunc *config_read, 
   10.12                                 PCIConfigWriteFunc *config_write);
   10.13  
   10.14 +void pci_hide_device(PCIDevice *pci_dev);
   10.15 +
   10.16  void pci_register_io_region(PCIDevice *pci_dev, int region_num, 
   10.17                              uint32_t size, int type, 
   10.18                              PCIMapIORegionFunc *map_func);
   10.19 @@ -850,6 +854,22 @@ void pci_info(void);
   10.20  PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint32_t id,
   10.21                          pci_map_irq_fn map_irq, const char *name);
   10.22  
   10.23 +/* PCI slot 6~7 support ACPI PCI hot plug */
   10.24 +#define PHP_SLOT_START  (6)
   10.25 +#define PHP_SLOT_END    (8)
   10.26 +#define PHP_SLOT_LEN    (PHP_SLOT_END - PHP_SLOT_START)
   10.27 +#define PHP_TO_PCI_SLOT(x) (x + PHP_SLOT_START)
   10.28 +#define PCI_TO_PHP_SLOT(x) (x - PHP_SLOT_START)
   10.29 +#define PHP_DEVFN_START (PHP_SLOT_START << 3)
   10.30 +#define PHP_DEVFN_END   (PHP_SLOT_END << 3)
   10.31 +
   10.32 +int insert_to_pci_slot(char*);
   10.33 +int test_pci_slot(int);
   10.34 +int bdf_to_slot(char*);
   10.35 +int power_on_php_slot(int);
   10.36 +int power_off_php_slot(int);
   10.37 +void pt_uninit(void);
   10.38 +
   10.39  /* prep_pci.c */
   10.40  PCIBus *pci_prep_init(void);
   10.41  
   10.42 @@ -1120,6 +1140,9 @@ void tpm_tis_init(SetIRQFunc *set_irq, v
   10.43  
   10.44  /* piix4acpi.c */
   10.45  extern void pci_piix4_acpi_init(PCIBus *bus, int devfn);
   10.46 +void acpi_php_add(int);
   10.47 +void acpi_php_del(int);
   10.48 +
   10.49  
   10.50  /* pc.c */
   10.51  extern QEMUMachine pc_machine;
   10.52 @@ -1320,6 +1343,9 @@ void do_usb_add(const char *devname);
   10.53  void do_usb_del(const char *devname);
   10.54  void usb_info(void);
   10.55  
   10.56 +void do_pci_add(char *devname);
   10.57 +void do_pci_del(char *devname);
   10.58 +
   10.59  /* scsi-disk.c */
   10.60  enum scsi_reason {
   10.61      SCSI_REASON_DONE, /* Command complete.  */
   10.62 @@ -1466,10 +1492,12 @@ void readline_start(const char *prompt, 
   10.63  void xenstore_parse_domain_config(int domid);
   10.64  int xenstore_fd(void);
   10.65  void xenstore_process_event(void *opaque);
   10.66 +void xenstore_record_dm(char *subpath, char *state);
   10.67  void xenstore_record_dm_state(char *state);
   10.68  void xenstore_check_new_media_present(int timeout);
   10.69  void xenstore_write_vncport(int vnc_display);
   10.70  void xenstore_read_vncpasswd(int domid, char *pwbuf, size_t pwbuflen);
   10.71 +void xenstore_write_vslots(char *vslots);
   10.72  
   10.73  int xenstore_domain_has_devtype(struct xs_handle *handle,
   10.74                                  const char *devtype);
    11.1 --- a/tools/ioemu/xenstore.c	Fri Feb 15 12:50:55 2008 +0000
    11.2 +++ b/tools/ioemu/xenstore.c	Fri Feb 15 14:13:17 2008 +0000
    11.3 @@ -79,6 +79,8 @@ static void waitForDevice(char *fn)
    11.4      return;
    11.5  }
    11.6  
    11.7 +#define DIRECT_PCI_STR_LEN 160
    11.8 +char direct_pci_str[DIRECT_PCI_STR_LEN];
    11.9  void xenstore_parse_domain_config(int domid)
   11.10  {
   11.11      char **e = NULL;
   11.12 @@ -86,7 +88,7 @@ void xenstore_parse_domain_config(int do
   11.13      char *fpath = NULL, *bpath = NULL,
   11.14          *dev = NULL, *params = NULL, *type = NULL, *drv = NULL;
   11.15      int i, is_scsi, is_hdN = 0;
   11.16 -    unsigned int len, num, hd_index;
   11.17 +    unsigned int len, num, hd_index, pci_devid = 0;
   11.18      BlockDriverState *bs;
   11.19  
   11.20      for(i = 0; i < MAX_DISKS + MAX_SCSI_DISKS; i++)
   11.21 @@ -250,6 +252,38 @@ void xenstore_parse_domain_config(int do
   11.22          fprintf(logfile, "Watching %s\n", buf);
   11.23      }
   11.24  
   11.25 +    /* get the pci pass-through parameter */
   11.26 +    if (pasprintf(&buf, "/local/domain/0/backend/pci/%u/%u/num_devs",
   11.27 +                  domid, pci_devid) == -1)
   11.28 +        goto out;
   11.29 +
   11.30 +    free(params);
   11.31 +    params = xs_read(xsh, XBT_NULL, buf, &len);
   11.32 +    if (params == NULL)
   11.33 +        goto out;
   11.34 +    num = atoi(params);
   11.35 +
   11.36 +    for ( i = 0; i < num; i++ ) {
   11.37 +        if (pasprintf(&buf, "/local/domain/0/backend/pci/%u/%u/dev-%d",
   11.38 +                    domid, pci_devid, i) != -1) {
   11.39 +            free(dev);
   11.40 +            dev = xs_read(xsh, XBT_NULL, buf, &len);
   11.41 +
   11.42 +            if ( strlen(dev) + strlen(direct_pci_str) > DIRECT_PCI_STR_LEN ) {
   11.43 +                fprintf(stderr, "qemu: too many pci pass-through devices\n");
   11.44 +                memset(direct_pci_str, 0, DIRECT_PCI_STR_LEN);
   11.45 +                goto out;
   11.46 +            }
   11.47 +
   11.48 +            /* append to direct_pci_str */
   11.49 +            if ( dev ) {
   11.50 +                strcat(direct_pci_str, dev);
   11.51 +                strcat(direct_pci_str, "-");
   11.52 +            }
   11.53 +        }
   11.54 +    }
   11.55 +
   11.56 +
   11.57   out:
   11.58      free(type);
   11.59      free(params);
   11.60 @@ -388,7 +422,7 @@ void xenstore_process_logdirty_event(voi
   11.61  /* Accept state change commands from the control tools */
   11.62  static void xenstore_process_dm_command_event(void)
   11.63  {
   11.64 -    char *path = NULL, *command = NULL;
   11.65 +    char *path = NULL, *command = NULL, *par = NULL;
   11.66      unsigned int len;
   11.67      extern int suspend_requested;
   11.68  
   11.69 @@ -407,6 +441,34 @@ static void xenstore_process_dm_command_
   11.70      } else if (!strncmp(command, "continue", len)) {
   11.71          fprintf(logfile, "dm-command: continue after state save\n");
   11.72          suspend_requested = 0;
   11.73 +    } else if (!strncmp(command, "pci-rem", len)) {
   11.74 +        fprintf(logfile, "dm-command: hot remove pass-through pci dev \n");
   11.75 +
   11.76 +        if (pasprintf(&path, 
   11.77 +                      "/local/domain/0/device-model/%u/parameter", domid) == -1) {
   11.78 +            fprintf(logfile, "out of memory reading dm command parameter\n");
   11.79 +            goto out;
   11.80 +        }
   11.81 +        par = xs_read(xsh, XBT_NULL, path, &len);
   11.82 +        if (!par)
   11.83 +            goto out;
   11.84 +
   11.85 +        do_pci_del(par);
   11.86 +        free(par);
   11.87 +    } else if (!strncmp(command, "pci-ins", len)) {
   11.88 +        fprintf(logfile, "dm-command: hot insert pass-through pci dev \n");
   11.89 +
   11.90 +        if (pasprintf(&path, 
   11.91 +                      "/local/domain/0/device-model/%u/parameter", domid) == -1) {
   11.92 +            fprintf(logfile, "out of memory reading dm command parameter\n");
   11.93 +            goto out;
   11.94 +        }
   11.95 +        par = xs_read(xsh, XBT_NULL, path, &len);
   11.96 +        if (!par)
   11.97 +            goto out;
   11.98 +
   11.99 +        do_pci_add(par);
  11.100 +        free(par);
  11.101      } else {
  11.102          fprintf(logfile, "dm-command: unknown command\"%*s\"\n", len, command);
  11.103      }
  11.104 @@ -416,22 +478,27 @@ static void xenstore_process_dm_command_
  11.105      free(command);
  11.106  }
  11.107  
  11.108 -void xenstore_record_dm_state(char *state)
  11.109 +void xenstore_record_dm(char *subpath, char *state)
  11.110  {
  11.111      char *path = NULL;
  11.112  
  11.113      if (pasprintf(&path, 
  11.114 -                  "/local/domain/0/device-model/%u/state", domid) == -1) {
  11.115 -        fprintf(logfile, "out of memory recording dm state\n");
  11.116 +                  "/local/domain/0/device-model/%u/%s", domid, subpath) == -1) {
  11.117 +        fprintf(logfile, "out of memory recording dm \n");
  11.118          goto out;
  11.119      }
  11.120      if (!xs_write(xsh, XBT_NULL, path, state, strlen(state)))
  11.121 -        fprintf(logfile, "error recording dm state\n");
  11.122 +        fprintf(logfile, "error recording dm \n");
  11.123  
  11.124   out:
  11.125      free(path);
  11.126  }
  11.127  
  11.128 +void xenstore_record_dm_state(char *state)
  11.129 +{
  11.130 +    xenstore_record_dm("state", state);
  11.131 +}
  11.132 +
  11.133  void xenstore_process_event(void *opaque)
  11.134  {
  11.135      char **vec, *offset, *bpath = NULL, *buf = NULL, *drv = NULL, *image = NULL;
  11.136 @@ -522,6 +589,23 @@ void xenstore_write_vncport(int display)
  11.137      free(buf);
  11.138  }
  11.139  
  11.140 +void xenstore_write_vslots(char *vslots)
  11.141 +{
  11.142 +    char *path = NULL;
  11.143 +    int pci_devid = 0;
  11.144 +
  11.145 +    if (pasprintf(&path, 
  11.146 +                  "/local/domain/0/backend/pci/%u/%u/vslots", domid, pci_devid) == -1) {
  11.147 +        fprintf(logfile, "out of memory when updating vslots.\n");
  11.148 +        goto out;
  11.149 +    }
  11.150 +    if (!xs_write(xsh, XBT_NULL, path, vslots, strlen(vslots)))
  11.151 +        fprintf(logfile, "error updating vslots \n");
  11.152 +
  11.153 + out:
  11.154 +    free(path);
  11.155 +}
  11.156 +
  11.157  void xenstore_read_vncpasswd(int domid, char *pwbuf, size_t pwbuflen)
  11.158  {
  11.159      char *buf = NULL, *path, *uuid = NULL, *passwd = NULL;
    12.1 --- a/tools/libxc/xc_domain.c	Fri Feb 15 12:50:55 2008 +0000
    12.2 +++ b/tools/libxc/xc_domain.c	Fri Feb 15 14:13:17 2008 +0000
    12.3 @@ -762,6 +762,20 @@ int xc_test_assign_device(
    12.4      return do_domctl(xc_handle, &domctl);
    12.5  }
    12.6  
    12.7 +int xc_deassign_device(
    12.8 +    int xc_handle,
    12.9 +    uint32_t domid,
   12.10 +    uint32_t machine_bdf)
   12.11 +{
   12.12 +    DECLARE_DOMCTL;
   12.13 +
   12.14 +    domctl.cmd = XEN_DOMCTL_deassign_device;
   12.15 +    domctl.domain = domid;
   12.16 +    domctl.u.assign_device.machine_bdf = machine_bdf;
   12.17 + 
   12.18 +    return do_domctl(xc_handle, &domctl);
   12.19 +}
   12.20 +
   12.21  /* Pass-through: binds machine irq to guests irq */
   12.22  int xc_domain_bind_pt_irq(
   12.23      int xc_handle,
   12.24 @@ -797,6 +811,36 @@ int xc_domain_bind_pt_irq(
   12.25      return rc;
   12.26  }
   12.27  
   12.28 +int xc_domain_unbind_pt_irq(
   12.29 +    int xc_handle,
   12.30 +    uint32_t domid,
   12.31 +    uint8_t machine_irq,
   12.32 +    uint8_t irq_type,
   12.33 +    uint8_t bus,
   12.34 +    uint8_t device,
   12.35 +    uint8_t intx,
   12.36 +    uint8_t isa_irq)
   12.37 +{
   12.38 +    int rc;
   12.39 +    xen_domctl_bind_pt_irq_t * bind;
   12.40 +    DECLARE_DOMCTL;
   12.41 +
   12.42 +    domctl.cmd = XEN_DOMCTL_unbind_pt_irq;
   12.43 +    domctl.domain = (domid_t)domid;
   12.44 +
   12.45 +    bind = &(domctl.u.bind_pt_irq);
   12.46 +    bind->hvm_domid = domid;
   12.47 +    bind->irq_type = irq_type;
   12.48 +    bind->machine_irq = machine_irq;
   12.49 +    bind->u.pci.bus = bus;
   12.50 +    bind->u.pci.device = device;    
   12.51 +    bind->u.pci.intx = intx;
   12.52 +    bind->u.isa.isa_irq = isa_irq;
   12.53 +    
   12.54 +    rc = do_domctl(xc_handle, &domctl);
   12.55 +    return rc;
   12.56 +}
   12.57 +
   12.58  int xc_domain_bind_pt_pci_irq(
   12.59      int xc_handle,
   12.60      uint32_t domid,
    13.1 --- a/tools/libxc/xenctrl.h	Fri Feb 15 12:50:55 2008 +0000
    13.2 +++ b/tools/libxc/xenctrl.h	Fri Feb 15 14:13:17 2008 +0000
    13.3 @@ -914,6 +914,10 @@ int xc_test_assign_device(int xc_handle,
    13.4                            uint32_t domid,
    13.5                            uint32_t machine_bdf);
    13.6  
    13.7 +int xc_deassign_device(int xc_handle,
    13.8 +                     uint32_t domid,
    13.9 +                     uint32_t machine_bdf);
   13.10 +
   13.11  int xc_domain_memory_mapping(int xc_handle,
   13.12                               uint32_t domid,
   13.13                               unsigned long first_gfn,
   13.14 @@ -937,6 +941,15 @@ int xc_domain_bind_pt_irq(int xc_handle,
   13.15                            uint8_t intx,
   13.16                            uint8_t isa_irq);
   13.17  
   13.18 +int xc_domain_unbind_pt_irq(int xc_handle,
   13.19 +                          uint32_t domid,
   13.20 +                          uint8_t machine_irq,
   13.21 +                          uint8_t irq_type,
   13.22 +                          uint8_t bus,
   13.23 +                          uint8_t device,
   13.24 +                          uint8_t intx,
   13.25 +                          uint8_t isa_irq);
   13.26 +
   13.27  int xc_domain_bind_pt_pci_irq(int xc_handle,
   13.28                                uint32_t domid,
   13.29                                uint8_t machine_irq,
    14.1 --- a/tools/python/xen/xend/XendDomainInfo.py	Fri Feb 15 12:50:55 2008 +0000
    14.2 +++ b/tools/python/xen/xend/XendDomainInfo.py	Fri Feb 15 14:13:17 2008 +0000
    14.3 @@ -516,6 +516,131 @@ class XendDomainInfo:
    14.4          asserts.isCharConvertible(key)
    14.5          self.storeDom("control/sysrq", '%c' % key)
    14.6  
    14.7 +    def sync_pcidev_info(self):
    14.8 +
    14.9 +        if not self.info.is_hvm():
   14.10 +            return
   14.11 +
   14.12 +        devid = '0'
   14.13 +        dev_info = self._getDeviceInfo_pci(devid)
   14.14 +        if dev_info is None:
   14.15 +            return
   14.16 +
   14.17 +        # get the virtual slot info from xenstore
   14.18 +        dev_uuid = sxp.child_value(dev_info, 'uuid')
   14.19 +        pci_conf = self.info['devices'][dev_uuid][1]
   14.20 +        pci_devs = pci_conf['devs']
   14.21 +
   14.22 +        count = 0
   14.23 +        vslots = None
   14.24 +        while vslots is None and count < 20:
   14.25 +            vslots = xstransact.Read("/local/domain/0/backend/pci/%u/%s/vslots"
   14.26 +                              % (self.getDomid(), devid))
   14.27 +            time.sleep(0.1)
   14.28 +            count += 1
   14.29 +        if vslots is None:
   14.30 +            log.error("Device model didn't tell the vslots for PCI device")
   14.31 +            return
   14.32 +
   14.33 +        #delete last delim
   14.34 +        if vslots[-1] == ";":
   14.35 +            vslots = vslots[:-1]
   14.36 +
   14.37 +        slot_list = vslots.split(';')
   14.38 +        if len(slot_list) != len(pci_devs):
   14.39 +            log.error("Device model's pci dev num dismatch")
   14.40 +            return
   14.41 +
   14.42 +        #update the vslot info
   14.43 +        count = 0;
   14.44 +        for x in pci_devs:
   14.45 +            x['vslt'] = slot_list[count]
   14.46 +            count += 1
   14.47 +
   14.48 +
   14.49 +    def pci_device_create(self, dev_config):
   14.50 +        log.debug("XendDomainInfo.pci_device_create: %s" % scrub_password(dev_config))
   14.51 +
   14.52 +        if not self.info.is_hvm():
   14.53 +            raise VmError("only HVM guest support pci attach")
   14.54 +
   14.55 +        #all the PCI devs share one conf node
   14.56 +        devid = '0'
   14.57 +
   14.58 +        dev_type = sxp.name(dev_config)
   14.59 +        new_devs = sxp.child_value(dev_config, 'devs')
   14.60 +        new_dev = new_devs[0]
   14.61 +        dev_info = self._getDeviceInfo_pci(devid)#from self.info['devices']
   14.62 +
   14.63 +        #check conflict before trigger hotplug event
   14.64 +        if dev_info is not None:
   14.65 +            dev_uuid = sxp.child_value(dev_info, 'uuid')
   14.66 +            pci_conf = self.info['devices'][dev_uuid][1]
   14.67 +            pci_devs = pci_conf['devs']
   14.68 +            for x in pci_devs:
   14.69 +                if (int(x['vslt'], 16) == int(new_dev['vslt'], 16) and
   14.70 +                   int(x['vslt'], 16) != 0 ):
   14.71 +                    raise VmError("vslot %s already have a device." % (new_dev['vslt']))
   14.72 +
   14.73 +                if (int(x['domain'], 16) == int(new_dev['domain'], 16) and
   14.74 +                   int(x['bus'], 16)    == int(new_dev['bus'], 16) and
   14.75 +                   int(x['slot'], 16)   == int(new_dev['slot'], 16) and
   14.76 +                   int(x['func'], 16)   == int(new_dev['func'], 16) ):
   14.77 +                    raise VmError("device is already inserted")
   14.78 +
   14.79 +        # Test whether the devices can be assigned with VT-d
   14.80 +        pci_str = "%s, %s, %s, %s" % (new_dev['domain'],
   14.81 +                new_dev['bus'],
   14.82 +                new_dev['slot'],
   14.83 +                new_dev['func'])
   14.84 +        bdf = xc.test_assign_device(self.domid, pci_str)
   14.85 +        if bdf != 0:
   14.86 +            bus = (bdf >> 16) & 0xff
   14.87 +            devfn = (bdf >> 8) & 0xff
   14.88 +            dev = (devfn >> 3) & 0x1f
   14.89 +            func = devfn & 0x7
   14.90 +            raise VmError("Fail to hot insert device(%x:%x.%x): maybe VT-d is "
   14.91 +                          "not enabled, or the device is not exist, or it "
   14.92 +                          "has already been assigned to other domain"
   14.93 +                          % (bus, dev, func))
   14.94 +
   14.95 +        bdf_str = "%s:%s:%s.%s@%s" % (new_dev['domain'],
   14.96 +                new_dev['bus'],
   14.97 +                new_dev['slot'],
   14.98 +                new_dev['func'],
   14.99 +                new_dev['vslt'])
  14.100 +        self.image.signalDeviceModel('pci-ins', 'pci-inserted', bdf_str)
  14.101 +
  14.102 +        # update the virtual pci slot
  14.103 +        vslt = xstransact.Read("/local/domain/0/device-model/%i/parameter"
  14.104 +                          % self.getDomid())
  14.105 +        new_dev['vslt'] = vslt
  14.106 +
  14.107 +        if dev_info is None:
  14.108 +            # create a new one from scrach
  14.109 +            dev_cfg_sxp = [dev_type,
  14.110 +                ['dev',
  14.111 +                  ['domain', new_dev['domain']],
  14.112 +                  ['bus',    new_dev['bus']],
  14.113 +                  ['slot',   new_dev['slot']],
  14.114 +                  ['func',   new_dev['func']],
  14.115 +                  ['vslt',   new_dev['vslt']]
  14.116 +                ]]
  14.117 +            dev_uuid = self.info.device_add(dev_type, cfg_sxp = dev_cfg_sxp)
  14.118 +            dev_config_dict = self.info['devices'][dev_uuid][1]
  14.119 +            try:
  14.120 +                dev_config_dict['devid'] = devid = \
  14.121 +                    self._createDevice(dev_type, dev_config_dict)
  14.122 +                self._waitForDevice(dev_type, devid)
  14.123 +            except VmError, ex:
  14.124 +                raise ex
  14.125 +        else:
  14.126 +            # update the pci config to add the new dev
  14.127 +            pci_devs.extend(new_devs)
  14.128 +            self._reconfigureDevice('pci', devid, pci_conf)
  14.129 +
  14.130 +        return self.getDeviceController('pci').sxpr(devid)
  14.131 +
  14.132      def device_create(self, dev_config):
  14.133          """Create a new device.
  14.134  
  14.135 @@ -524,6 +649,11 @@ class XendDomainInfo:
  14.136          """
  14.137          log.debug("XendDomainInfo.device_create: %s" % scrub_password(dev_config))
  14.138          dev_type = sxp.name(dev_config)
  14.139 +
  14.140 +        if dev_type == 'pci':
  14.141 +            rc = self.pci_device_create(dev_config)
  14.142 +            return rc
  14.143 +
  14.144          dev_uuid = self.info.device_add(dev_type, cfg_sxp = dev_config)
  14.145          dev_config_dict = self.info['devices'][dev_uuid][1]
  14.146          log.debug("XendDomainInfo.device_create: %s" % scrub_password(dev_config_dict))
  14.147 @@ -584,10 +714,65 @@ class XendDomainInfo:
  14.148          for devclass in XendDevices.valid_devices():
  14.149              self.getDeviceController(devclass).waitForDevices()
  14.150  
  14.151 +    def destroyPCIDevice(self, vslot):
  14.152 +        log.debug("destroyPCIDevice called %s", vslot)
  14.153 +
  14.154 +        if not self.info.is_hvm():
  14.155 +            raise VmError("only HVM guest support pci detach")
  14.156 +
  14.157 +        #all the PCI devs share one conf node
  14.158 +        devid = '0'
  14.159 +        vslot = int(vslot)
  14.160 +        dev_info = self._getDeviceInfo_pci('0')#from self.info['devices']
  14.161 +        dev_uuid = sxp.child_value(dev_info, 'uuid')
  14.162 +
  14.163 +        #delete the pci bdf config under the pci device
  14.164 +        pci_conf = self.info['devices'][dev_uuid][1]
  14.165 +        pci_len = len(pci_conf['devs'])
  14.166 +
  14.167 +        #find the pass-through device with the virtual slot
  14.168 +        devnum = 0
  14.169 +        for x in pci_conf['devs']:
  14.170 +            if int(x['vslt'], 16) == vslot:
  14.171 +                break
  14.172 +            devnum += 1
  14.173 +
  14.174 +        if devnum >= pci_len:
  14.175 +            raise VmError("Device @ vslot 0x%x doesn't exist." % (vslot))
  14.176 +
  14.177 +        if vslot == 0:
  14.178 +            raise VmError("Device @ vslot 0x%x do not support hotplug." % (vslot))
  14.179 +
  14.180 +        bdf_str = "%s:%s:%s.%s" % (x['domain'], x['bus'], x['slot'], x['func'])
  14.181 +        log.info("destroyPCIDevice:%s:%s!", x, bdf_str)
  14.182 +
  14.183 +        self.image.signalDeviceModel('pci-rem', 'pci-removed', bdf_str)
  14.184 +
  14.185 +        if pci_len > 1:
  14.186 +            del pci_conf['devs'][devnum]
  14.187 +            self._reconfigureDevice('pci', devid, pci_conf)
  14.188 +        else:
  14.189 +            self.getDeviceController('pci').destroyDevice(devid, True)
  14.190 +            del self.info['devices'][dev_uuid]
  14.191 +            platform = self.info['platform']
  14.192 +            orig_dev_num = len(platform['pci'])
  14.193 +
  14.194 +            #need remove the pci config
  14.195 +            #TODO:can use this to keep some info to ask high level management tools to hot insert a new passthrough dev after migration
  14.196 +            if orig_dev_num != 0:
  14.197 +#                platform['pci'] = ["%dDEVs" % orig_dev_num]
  14.198 +                platform['pci'] = []
  14.199 +
  14.200 +        return 0
  14.201 +
  14.202      def destroyDevice(self, deviceClass, devid, force = False, rm_cfg = False):
  14.203          log.debug("XendDomainInfo.destroyDevice: deviceClass = %s, device = %s",
  14.204                    deviceClass, devid)
  14.205  
  14.206 +        if deviceClass == 'dpci':
  14.207 +            rc = self.destroyPCIDevice(devid)
  14.208 +            return rc
  14.209 +
  14.210          if rm_cfg:
  14.211              # Convert devid to device number.  A device number is
  14.212              # needed to remove its configuration.
  14.213 @@ -647,6 +832,14 @@ class XendDomainInfo:
  14.214          return rc
  14.215  
  14.216      def getDeviceSxprs(self, deviceClass):
  14.217 +        if deviceClass == 'pci':
  14.218 +            dev_info = self._getDeviceInfo_pci('0')#from self.info['devices']
  14.219 +            if dev_info is None:
  14.220 +                return []
  14.221 +            dev_uuid = sxp.child_value(dev_info, 'uuid')
  14.222 +            pci_devs = self.info['devices'][dev_uuid][1]['devs']
  14.223 +            pci_len = len(pci_devs)
  14.224 +            return pci_devs
  14.225          if self._stateGet() in (DOM_STATE_RUNNING, DOM_STATE_PAUSED, DOM_STATE_CRASHED):
  14.226              return self.getDeviceController(deviceClass).sxprs()
  14.227          else:
  14.228 @@ -683,6 +876,12 @@ class XendDomainInfo:
  14.229              if devid == dev:
  14.230                  return dev_info
  14.231  
  14.232 +    def _getDeviceInfo_pci(self, devid):
  14.233 +        for dev_type, dev_info in self.info.all_devices_sxpr():
  14.234 +            if dev_type != 'pci':
  14.235 +                continue
  14.236 +            return dev_info
  14.237 +        return None
  14.238  
  14.239      def setMemoryTarget(self, target):
  14.240          """Set the memory target of this domain.
  14.241 @@ -1543,6 +1742,9 @@ class XendDomainInfo:
  14.242          if self.image:
  14.243              self.image.createDeviceModel()
  14.244  
  14.245 +        #if have pass-through devs, need the virtual pci slots info from qemu
  14.246 +        self.sync_pcidev_info()
  14.247 +
  14.248      def _releaseDevices(self, suspend = False):
  14.249          """Release all domain's devices.  Nothrow guarantee."""
  14.250          if self.image:
    15.1 --- a/tools/python/xen/xend/image.py	Fri Feb 15 12:50:55 2008 +0000
    15.2 +++ b/tools/python/xen/xend/image.py	Fri Feb 15 14:13:17 2008 +0000
    15.3 @@ -300,23 +300,42 @@ class ImageHandler:
    15.4          self.vm.storeDom("image/device-model-pid", self.pid)
    15.5          log.info("device model pid: %d", self.pid)
    15.6  
    15.7 -    def saveDeviceModel(self):
    15.8 +    def signalDeviceModel(self, cmd, ret, par = None):
    15.9          if self.device_model is None:
   15.10              return
   15.11 -        # Signal the device model to pause itself and save its state
   15.12 +        # Signal the device model to for action
   15.13 +        if cmd is '' or ret is '':
   15.14 +            raise VmError('need valid command and result when signal device model')
   15.15 +
   15.16 +        orig_state = xstransact.Read("/local/domain/0/device-model/%i/state"
   15.17 +                                % self.vm.getDomid())
   15.18 +
   15.19 +        if par is not None:
   15.20 +            xstransact.Store("/local/domain/0/device-model/%i"
   15.21 +                             % self.vm.getDomid(), ('parameter', par))
   15.22 +
   15.23          xstransact.Store("/local/domain/0/device-model/%i"
   15.24 -                         % self.vm.getDomid(), ('command', 'save'))
   15.25 +                         % self.vm.getDomid(), ('command', cmd))
   15.26          # Wait for confirmation.  Could do this with a watch but we'd
   15.27          # still end up spinning here waiting for the watch to fire. 
   15.28          state = ''
   15.29          count = 0
   15.30 -        while state != 'paused':
   15.31 +        while state != ret:
   15.32              state = xstransact.Read("/local/domain/0/device-model/%i/state"
   15.33                                      % self.vm.getDomid())
   15.34              time.sleep(0.1)
   15.35              count += 1
   15.36              if count > 100:
   15.37 -                raise VmError('Timed out waiting for device model to save')
   15.38 +                raise VmError('Timed out waiting for device model action')
   15.39 +
   15.40 +        #resotre orig state
   15.41 +        xstransact.Store("/local/domain/0/device-model/%i"
   15.42 +                         % self.vm.getDomid(), ('state', orig_state))
   15.43 +        log.info("signalDeviceModel:restore dm state to %s", orig_state)
   15.44 +
   15.45 +    def saveDeviceModel(self):
   15.46 +        # Signal the device model to pause itself and save its state
   15.47 +        self.signalDeviceModel('save', 'paused')
   15.48  
   15.49      def resumeDeviceModel(self):
   15.50          if self.device_model is None:
   15.51 @@ -479,7 +498,7 @@ class HVMImageHandler(ImageHandler):
   15.52  
   15.53          dmargs = [ 'boot', 'fda', 'fdb', 'soundhw',
   15.54                     'localtime', 'serial', 'stdvga', 'isa',
   15.55 -                   'acpi', 'usb', 'usbdevice', 'pci' ]
   15.56 +                   'acpi', 'usb', 'usbdevice' ]
   15.57  
   15.58          for a in dmargs:
   15.59              v = vmConfig['platform'].get(a)
    16.1 --- a/tools/python/xen/xend/server/DevController.py	Fri Feb 15 12:50:55 2008 +0000
    16.2 +++ b/tools/python/xen/xend/server/DevController.py	Fri Feb 15 14:13:17 2008 +0000
    16.3 @@ -412,6 +412,14 @@ class DevController:
    16.4          return result
    16.5  
    16.6  
    16.7 +    def removeBackend(self, devid, *args):
    16.8 +        frontpath = self.frontendPath(devid)
    16.9 +        backpath = xstransact.Read(frontpath, "backend")
   16.10 +        if backpath:
   16.11 +            return xstransact.Remove(backpath, *args)
   16.12 +        else:
   16.13 +            raise VmError("Device %s not connected" % devid)
   16.14 +
   16.15      def readBackend(self, devid, *args):
   16.16          frontpath = self.frontendPath(devid)
   16.17          backpath = xstransact.Read(frontpath, "backend")
    17.1 --- a/tools/python/xen/xend/server/pciif.py	Fri Feb 15 12:50:55 2008 +0000
    17.2 +++ b/tools/python/xen/xend/server/pciif.py	Fri Feb 15 14:13:17 2008 +0000
    17.3 @@ -18,6 +18,7 @@
    17.4  
    17.5  
    17.6  import types
    17.7 +import time
    17.8  
    17.9  from xen.xend import sxp
   17.10  from xen.xend.XendError import VmError
   17.11 @@ -62,25 +63,62 @@ class PciController(DevController):
   17.12              
   17.13          back = {}
   17.14          pcidevid = 0
   17.15 +        vslots = ""
   17.16          for pci_config in config.get('devs', []):
   17.17              domain = parse_hex(pci_config.get('domain', 0))
   17.18              bus = parse_hex(pci_config.get('bus', 0))
   17.19              slot = parse_hex(pci_config.get('slot', 0))
   17.20              func = parse_hex(pci_config.get('func', 0))            
   17.21 +
   17.22 +            vslt = pci_config.get('vslt')
   17.23 +            if vslt is not None:
   17.24 +                vslots = vslots + vslt + ";"
   17.25 +
   17.26              self.setupDevice(domain, bus, slot, func)
   17.27              back['dev-%i' % pcidevid] = "%04x:%02x:%02x.%02x" % \
   17.28                                          (domain, bus, slot, func)
   17.29              pcidevid += 1
   17.30  
   17.31 +        if vslots != "":
   17.32 +            back['vslots'] = vslots
   17.33 +
   17.34          back['num_devs']=str(pcidevid)
   17.35          back['uuid'] = config.get('uuid','')
   17.36          return (0, back, {})
   17.37  
   17.38 +    def reconfigureDevice(self, _, config):
   17.39 +        """@see DevController.reconfigureDevice"""
   17.40 +        #currently only support config changes by hot insert/remove pass-through dev
   17.41 +        #delete all the devices in xenstore
   17.42 +        (devid, new_back, new_front) = self.getDeviceDetails(config)
   17.43 +        num_devs = self.readBackend(devid, 'num_devs')
   17.44 +        for i in range(int(num_devs)):
   17.45 +            self.removeBackend(devid, 'dev-%d' % i)
   17.46 +        self.removeBackend(devid, 'num_devs')
   17.47 +
   17.48 +        #create new devices config
   17.49 +        num_devs = new_back['num_devs']
   17.50 +        for i in range(int(num_devs)):
   17.51 +            dev_no = 'dev-%d' % i
   17.52 +            self.writeBackend(devid, dev_no, new_back[dev_no])
   17.53 +        self.writeBackend(devid, 'num_devs', num_devs)
   17.54 +
   17.55 +        if new_back['vslots'] is not None:
   17.56 +            self.writeBackend(devid, 'vslots', new_back['vslots'])
   17.57 +
   17.58 +        return new_back.get('uuid')
   17.59 +
   17.60      def getDeviceConfiguration(self, devid, transaction = None):
   17.61          result = DevController.getDeviceConfiguration(self, devid, transaction)
   17.62          num_devs = self.readBackend(devid, 'num_devs')
   17.63          pci_devs = []
   17.64          
   17.65 +        vslots = self.readBackend(devid, 'vslots')
   17.66 +        if vslots is not None:
   17.67 +            if vslots[-1] == ";":
   17.68 +                vslots = vslots[:-1]
   17.69 +            slot_list = vslots.split(';')
   17.70 +
   17.71          for i in range(int(num_devs)):
   17.72              dev_config = self.readBackend(devid, 'dev-%d' % i)
   17.73  
   17.74 @@ -91,10 +129,16 @@ class PciController(DevController):
   17.75              
   17.76              if pci_match!=None:
   17.77                  pci_dev_info = pci_match.groupdict()
   17.78 -                pci_devs.append({'domain': '0x%(domain)s' % pci_dev_info,
   17.79 +                dev_dict = {'domain': '0x%(domain)s' % pci_dev_info,
   17.80                                   'bus': '0x%(bus)s' % pci_dev_info,
   17.81                                   'slot': '0x%(slot)s' % pci_dev_info,
   17.82 -                                 'func': '0x%(func)s' % pci_dev_info})
   17.83 +                                 'func': '0x%(func)s' % pci_dev_info}
   17.84 +
   17.85 +                #append vslot info
   17.86 +                if vslots is not None:
   17.87 +                    dev_dict['vslt'] = slot_list[i]
   17.88 +
   17.89 +                pci_devs.append(dev_dict)
   17.90  
   17.91          result['devs'] = pci_devs
   17.92          result['uuid'] = self.readBackend(devid, 'uuid')
    18.1 --- a/tools/python/xen/xm/main.py	Fri Feb 15 12:50:55 2008 +0000
    18.2 +++ b/tools/python/xen/xm/main.py	Fri Feb 15 14:13:17 2008 +0000
    18.3 @@ -175,6 +175,12 @@ SUBCOMMAND_HELP = {
    18.4      'vnet-delete'   :  ('<VnetId>', 'Delete a Vnet.'),
    18.5      'vnet-list'     :  ('[-l|--long]', 'List Vnets.'),
    18.6      'vtpm-list'     :  ('<Domain> [--long]', 'List virtual TPM devices.'),
    18.7 +    'pci-attach '   :  ('<Domain> <dom> <bus> <slot> <func> [virtual slot]',
    18.8 +                        'Insert a new pass-through pci device.'),
    18.9 +    'pci-detach '   :  ('<Domain> <virtual slot>',
   18.10 +                        'Remove a domain\'s pass-through pci device.'),
   18.11 +    'pci-list'     :  ('<Domain>',
   18.12 +                        'List pass-through pci devices for a domain.'),
   18.13  
   18.14      # security
   18.15  
   18.16 @@ -335,6 +341,9 @@ device_commands = [
   18.17      "network-detach",
   18.18      "network-list",
   18.19      "vtpm-list",
   18.20 +    "pci-attach",
   18.21 +    "pci-detach",
   18.22 +    "pci-list",
   18.23      ]
   18.24  
   18.25  vnet_commands = [
   18.26 @@ -2051,6 +2060,31 @@ def xm_vtpm_list(args):
   18.27                     % ni)
   18.28  
   18.29  
   18.30 +def xm_pci_list(args):
   18.31 +    (use_long, params) = arg_check_for_resource_list(args, "pci-list")
   18.32 +
   18.33 +    dom = params[0]
   18.34 +
   18.35 +    devs = server.xend.domain.getDeviceSxprs(dom, 'pci')
   18.36 +
   18.37 +    if len(devs) == 0:
   18.38 +        return
   18.39 +
   18.40 +    has_vslt = devs[0].has_key('vslt')
   18.41 +    if has_vslt:
   18.42 +        hdr_str = 'VSlt domain   bus   slot   func'
   18.43 +        fmt_str =  "%(vslt)-3s    %(domain)-3s  %(bus)-3s   %(slot)-3s    %(func)-3s    "
   18.44 +    else:
   18.45 +        hdr_str = 'domain   bus   slot   func'
   18.46 +        fmt_str =  "%(domain)-3s  %(bus)-3s   %(slot)-3s    %(func)-3s    "
   18.47 +    hdr = 0
   18.48 +
   18.49 +    for x in devs:
   18.50 +        if hdr == 0:
   18.51 +            print (hdr_str)
   18.52 +            hdr = 1
   18.53 +        print ( fmt_str % x )
   18.54 +
   18.55  def parse_block_configuration(args):
   18.56      dom = args[0]
   18.57  
   18.58 @@ -2198,6 +2232,29 @@ def xm_network_attach(args):
   18.59              vif.append(vif_param)
   18.60          server.xend.domain.device_create(dom, vif)
   18.61  
   18.62 +def parse_pci_configuration(args):
   18.63 +    dom = args[0]
   18.64 +
   18.65 +    if len(args) == 6:
   18.66 +        vslt = args[5]
   18.67 +    else:
   18.68 +        vslt = '0x0' #chose a free virtual PCI slot
   18.69 +
   18.70 +    pci = ['pci',
   18.71 +          ['devs',
   18.72 +            [{'domain': "0x%x" % int(args[1], 16),
   18.73 +              'bus':    "0x%x" % int(args[2], 16),
   18.74 +              'slot':   "0x%x" % int(args[3], 16),
   18.75 +              'func':   "0x%x" % int(args[4], 16),
   18.76 +              'vslt':   "0x%x" % int(vslt,    16)}]
   18.77 +          ]]
   18.78 +
   18.79 +    return (dom, pci)
   18.80 +
   18.81 +def xm_pci_attach(args):
   18.82 +    arg_check(args, 'xm_pci_attach', 5, 6)
   18.83 +    (dom, pci) = parse_pci_configuration(args)
   18.84 +    server.xend.domain.device_create(dom, pci)
   18.85  
   18.86  def detach(args, deviceClass):
   18.87      rm_cfg = True
   18.88 @@ -2263,6 +2320,12 @@ def xm_network_detach(args):
   18.89          detach(args, 'vif')
   18.90  
   18.91  
   18.92 +def xm_pci_detach(args):
   18.93 +    arg_check(args, 'xm_pci_detach', 2, 2)
   18.94 +    dom = args[0]
   18.95 +    dev = args[1]
   18.96 +    server.xend.domain.destroyDevice(dom, 'dpci', dev)
   18.97 +
   18.98  def xm_vnet_list(args):
   18.99      xenapi_unsupported()
  18.100      try:
  18.101 @@ -2452,6 +2515,10 @@ commands = {
  18.102      "vnet-delete": xm_vnet_delete,
  18.103      # vtpm
  18.104      "vtpm-list": xm_vtpm_list,
  18.105 +    #pci
  18.106 +    "pci-attach": xm_pci_attach,
  18.107 +    "pci-detach": xm_pci_detach,
  18.108 +    "pci-list": xm_pci_list,
  18.109      }
  18.110  
  18.111  ## The commands supported by a separate argument parser in xend.xm.
    19.1 --- a/xen/arch/x86/domctl.c	Fri Feb 15 12:50:55 2008 +0000
    19.2 +++ b/xen/arch/x86/domctl.c	Fri Feb 15 14:13:17 2008 +0000
    19.3 @@ -580,6 +580,34 @@ long arch_do_domctl(
    19.4      }
    19.5      break;
    19.6  
    19.7 +    case XEN_DOMCTL_deassign_device:
    19.8 +    {
    19.9 +        struct domain *d;
   19.10 +        u8 bus, devfn;
   19.11 +
   19.12 +        ret = -EINVAL;
   19.13 +        if ( !iommu_enabled )
   19.14 +            break;
   19.15 +
   19.16 +        if ( unlikely((d = get_domain_by_id(domctl->domain)) == NULL) )
   19.17 +        {
   19.18 +            gdprintk(XENLOG_ERR,
   19.19 +                "XEN_DOMCTL_deassign_device: get_domain_by_id() failed\n"); 
   19.20 +            break;
   19.21 +        }
   19.22 +        bus = (domctl->u.assign_device.machine_bdf >> 16) & 0xff;
   19.23 +        devfn = (domctl->u.assign_device.machine_bdf >> 8) & 0xff;
   19.24 +
   19.25 +        if ( !device_assigned(bus, devfn) )
   19.26 +            break;
   19.27 +
   19.28 +        reassign_device_ownership(d, dom0, bus, devfn);
   19.29 +        gdprintk(XENLOG_INFO, "XEN_DOMCTL_deassign_device: bdf = %x:%x:%x\n",
   19.30 +            bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
   19.31 +        put_domain(d);
   19.32 +    }
   19.33 +    break;
   19.34 +
   19.35      case XEN_DOMCTL_bind_pt_irq:
   19.36      {
   19.37          struct domain * d;
   19.38 @@ -595,6 +623,23 @@ long arch_do_domctl(
   19.39              gdprintk(XENLOG_ERR, "pt_irq_create_bind failed!\n");
   19.40          rcu_unlock_domain(d);
   19.41      }
   19.42 +    break;    
   19.43 +
   19.44 +    case XEN_DOMCTL_unbind_pt_irq:
   19.45 +    {
   19.46 +        struct domain * d;
   19.47 +        xen_domctl_bind_pt_irq_t * bind;
   19.48 +
   19.49 +        ret = -ESRCH;
   19.50 +        if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL )
   19.51 +            break;
   19.52 +        bind = &(domctl->u.bind_pt_irq);
   19.53 +        if ( iommu_enabled )
   19.54 +            ret = pt_irq_destroy_bind_vtd(d, bind);
   19.55 +        if ( ret < 0 )
   19.56 +            gdprintk(XENLOG_ERR, "pt_irq_destroy_bind failed!\n");
   19.57 +        rcu_unlock_domain(d);
   19.58 +    }
   19.59      break;
   19.60  
   19.61      case XEN_DOMCTL_memory_mapping:
    20.1 --- a/xen/arch/x86/hvm/irq.c	Fri Feb 15 12:50:55 2008 +0000
    20.2 +++ b/xen/arch/x86/hvm/irq.c	Fri Feb 15 14:13:17 2008 +0000
    20.3 @@ -211,8 +211,7 @@ void hvm_set_pci_link_route(struct domai
    20.4              clear_bit(old_isa_irq, &hvm_irq->dpci->isairq_map);
    20.5  
    20.6          for ( i = 0; i < NR_LINK; i++ )
    20.7 -            if ( test_bit(i, &hvm_irq->dpci->link_map) &&
    20.8 -                 hvm_irq->pci_link.route[i] )
    20.9 +            if ( hvm_irq->dpci->link_cnt[i] && hvm_irq->pci_link.route[i] )
   20.10                  set_bit(hvm_irq->pci_link.route[i],
   20.11                          &hvm_irq->dpci->isairq_map);
   20.12      }
    21.1 --- a/xen/arch/x86/hvm/vmx/vtd/intel-iommu.c	Fri Feb 15 12:50:55 2008 +0000
    21.2 +++ b/xen/arch/x86/hvm/vmx/vtd/intel-iommu.c	Fri Feb 15 14:13:17 2008 +0000
    21.3 @@ -1441,6 +1441,8 @@ void reassign_device_ownership(
    21.4               bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
    21.5               source->domain_id, target->domain_id);
    21.6  
    21.7 +    pdev_flr(bus, devfn);
    21.8 +
    21.9      for_each_pdev( source, pdev )
   21.10      {
   21.11          if ( (pdev->bus != bus) || (pdev->devfn != devfn) )
   21.12 @@ -1476,7 +1478,6 @@ void return_devices_to_dom0(struct domai
   21.13          dprintk(XENLOG_INFO VTDPREFIX,
   21.14                  "return_devices_to_dom0: bdf = %x:%x:%x\n",
   21.15                  pdev->bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
   21.16 -        pdev_flr(pdev->bus, pdev->devfn);
   21.17          reassign_device_ownership(d, dom0, pdev->bus, pdev->devfn);
   21.18      }
   21.19  
   21.20 @@ -1941,7 +1942,6 @@ int intel_iommu_assign_device(struct dom
   21.21               "assign_device: bus = %x dev = %x func = %x\n",
   21.22               bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
   21.23  
   21.24 -    pdev_flr(bus, devfn);
   21.25      reassign_device_ownership(dom0, d, bus, devfn);
   21.26  
   21.27      /* Setup rmrr identify mapping */
    22.1 --- a/xen/arch/x86/hvm/vmx/vtd/io.c	Fri Feb 15 12:50:55 2008 +0000
    22.2 +++ b/xen/arch/x86/hvm/vmx/vtd/io.c	Fri Feb 15 14:13:17 2008 +0000
    22.3 @@ -101,7 +101,7 @@ int pt_irq_create_bind_vtd(
    22.4      intx = pt_irq_bind->u.pci.intx;
    22.5      guest_gsi = hvm_pci_intx_gsi(device, intx);
    22.6      link = hvm_pci_intx_link(device, intx);
    22.7 -    set_bit(link, hvm_irq_dpci->link_map);
    22.8 +    hvm_irq_dpci->link_cnt[link]++;
    22.9  
   22.10      digl = xmalloc(struct dev_intx_gsi_link);
   22.11      if ( !digl )
   22.12 @@ -137,6 +137,65 @@ int pt_irq_create_bind_vtd(
   22.13      return 0;
   22.14  }
   22.15  
   22.16 +int pt_irq_destroy_bind_vtd(
   22.17 +    struct domain *d, xen_domctl_bind_pt_irq_t *pt_irq_bind)
   22.18 +{
   22.19 +    struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
   22.20 +    uint32_t machine_gsi, guest_gsi;
   22.21 +    uint32_t device, intx, link;
   22.22 +    struct list_head *digl_list, *tmp;
   22.23 +    struct dev_intx_gsi_link *digl;
   22.24 +
   22.25 +    if ( hvm_irq_dpci == NULL )
   22.26 +        return 0;
   22.27 +
   22.28 +    machine_gsi = pt_irq_bind->machine_irq;
   22.29 +    device = pt_irq_bind->u.pci.device;
   22.30 +    intx = pt_irq_bind->u.pci.intx;
   22.31 +    guest_gsi = hvm_pci_intx_gsi(device, intx);
   22.32 +    link = hvm_pci_intx_link(device, intx);
   22.33 +    hvm_irq_dpci->link_cnt[link]--;
   22.34 +
   22.35 +    gdprintk(XENLOG_INFO,
   22.36 +            "pt_irq_destroy_bind_vtd: machine_gsi=%d, guest_gsi=%d, device=%d, intx=%d.\n",
   22.37 +            machine_gsi, guest_gsi, device, intx);
   22.38 +    memset(&hvm_irq_dpci->girq[guest_gsi], 0, sizeof(struct hvm_girq_dpci_mapping));
   22.39 +
   22.40 +    /* clear the mirq info */
   22.41 +    if ( hvm_irq_dpci->mirq[machine_gsi].valid )
   22.42 +    {
   22.43 +
   22.44 +        list_for_each_safe ( digl_list, tmp,
   22.45 +                &hvm_irq_dpci->mirq[machine_gsi].digl_list )
   22.46 +        {
   22.47 +            digl = list_entry(digl_list,
   22.48 +                    struct dev_intx_gsi_link, list);
   22.49 +            if ( digl->device == device &&
   22.50 +                 digl->intx   == intx &&
   22.51 +                 digl->link   == link &&
   22.52 +                 digl->gsi    == guest_gsi )
   22.53 +            {
   22.54 +                list_del(&digl->list);
   22.55 +                xfree(digl);
   22.56 +            }
   22.57 +        }
   22.58 +
   22.59 +        if ( list_empty(&hvm_irq_dpci->mirq[machine_gsi].digl_list) )
   22.60 +        {
   22.61 +            pirq_guest_unbind(d, machine_gsi);
   22.62 +            kill_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(machine_gsi)]);
   22.63 +            hvm_irq_dpci->mirq[machine_gsi].dom   = NULL;
   22.64 +            hvm_irq_dpci->mirq[machine_gsi].valid = 0;
   22.65 +        }
   22.66 +    }
   22.67 +
   22.68 +    gdprintk(XENLOG_INFO,
   22.69 +             "XEN_DOMCTL_irq_unmapping: m_irq = %x device = %x intx = %x\n",
   22.70 +             machine_gsi, device, intx);
   22.71 +
   22.72 +    return 0;
   22.73 +}
   22.74 +
   22.75  int hvm_do_IRQ_dpci(struct domain *d, unsigned int mirq)
   22.76  {
   22.77      struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
    23.1 --- a/xen/include/asm-x86/hvm/irq.h	Fri Feb 15 12:50:55 2008 +0000
    23.2 +++ b/xen/include/asm-x86/hvm/irq.h	Fri Feb 15 14:13:17 2008 +0000
    23.3 @@ -64,7 +64,7 @@ struct hvm_irq_dpci {
    23.4      /* Record of mapped ISA IRQs */
    23.5      DECLARE_BITMAP(isairq_map, NR_ISAIRQS);
    23.6      /* Record of mapped Links */
    23.7 -    DECLARE_BITMAP(link_map, NR_LINK);
    23.8 +    uint8_t link_cnt[NR_LINK];
    23.9      struct timer hvm_timer[NR_IRQS];
   23.10  };
   23.11  
    24.1 --- a/xen/include/asm-x86/iommu.h	Fri Feb 15 12:50:55 2008 +0000
    24.2 +++ b/xen/include/asm-x86/iommu.h	Fri Feb 15 14:13:17 2008 +0000
    24.3 @@ -74,6 +74,9 @@ int iommu_domain_init(struct domain *d);
    24.4  void iommu_domain_destroy(struct domain *d);
    24.5  int device_assigned(u8 bus, u8 devfn);
    24.6  int assign_device(struct domain *d, u8 bus, u8 devfn);
    24.7 +void reassign_device_ownership(struct domain *source,
    24.8 +                               struct domain *target,
    24.9 +                               u8 bus, u8 devfn);
   24.10  int iommu_map_page(struct domain *d, unsigned long gfn, unsigned long mfn);
   24.11  int iommu_unmap_page(struct domain *d, unsigned long gfn);
   24.12  void iommu_flush(struct domain *d, unsigned long gfn, u64 *p2m_entry);
   24.13 @@ -83,6 +86,8 @@ int hvm_do_IRQ_dpci(struct domain *d, un
   24.14  int dpci_ioport_intercept(ioreq_t *p);
   24.15  int pt_irq_create_bind_vtd(struct domain *d,
   24.16                             xen_domctl_bind_pt_irq_t *pt_irq_bind);
   24.17 +int pt_irq_destroy_bind_vtd(struct domain *d,
   24.18 +                            xen_domctl_bind_pt_irq_t *pt_irq_bind);
   24.19  unsigned int io_apic_read_remap_rte(
   24.20      unsigned int apic, unsigned int reg);
   24.21  void io_apic_write_remap_rte(unsigned int apic,
    25.1 --- a/xen/include/public/domctl.h	Fri Feb 15 12:50:55 2008 +0000
    25.2 +++ b/xen/include/public/domctl.h	Fri Feb 15 14:13:17 2008 +0000
    25.3 @@ -439,6 +439,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_domctl_sendt
    25.4  /* Assign PCI device to HVM guest. Sets up IOMMU structures. */
    25.5  #define XEN_DOMCTL_assign_device      37
    25.6  #define XEN_DOMCTL_test_assign_device 45
    25.7 +#define XEN_DOMCTL_deassign_device 47
    25.8  struct xen_domctl_assign_device {
    25.9      uint32_t  machine_bdf;   /* machine PCI ID of assigned device */
   25.10  };
   25.11 @@ -448,6 +449,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_domctl_assig
   25.12  
   25.13  /* Pass-through interrupts: bind real irq -> hvm devfn. */
   25.14  #define XEN_DOMCTL_bind_pt_irq       38
   25.15 +#define XEN_DOMCTL_unbind_pt_irq     48
   25.16  typedef enum pt_irq_type_e {
   25.17      PT_IRQ_TYPE_PCI,
   25.18      PT_IRQ_TYPE_ISA
    26.1 --- a/xen/include/public/hvm/ioreq.h	Fri Feb 15 12:50:55 2008 +0000
    26.2 +++ b/xen/include/public/hvm/ioreq.h	Fri Feb 15 14:13:17 2008 +0000
    26.3 @@ -118,6 +118,11 @@ struct buffered_piopage {
    26.4  #define ACPI_PM1A_EVT_BLK_ADDRESS           0x0000000000001f40
    26.5  #define ACPI_PM1A_CNT_BLK_ADDRESS           (ACPI_PM1A_EVT_BLK_ADDRESS + 0x04)
    26.6  #define ACPI_PM_TMR_BLK_ADDRESS             (ACPI_PM1A_EVT_BLK_ADDRESS + 0x08)
    26.7 +
    26.8 +#define ACPI_GPE0_BLK_ADDRESS               (ACPI_PM_TMR_BLK_ADDRESS + 0x20)
    26.9 +
   26.10 +#define ACPI_GPE0_BLK_LEN                   0x08
   26.11 +
   26.12  #endif /* defined(__i386__) || defined(__x86_64__) */
   26.13  
   26.14  #endif /* _IOREQ_H_ */