All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
@ 2013-10-16  6:30 Gonglei (Arei)
  2013-10-16  9:13 ` Fabio Fantoni
                   ` (5 more replies)
  0 siblings, 6 replies; 38+ messages in thread
From: Gonglei (Arei) @ 2013-10-16  6:30 UTC (permalink / raw)
  To: xen-devel
  Cc: Konrad Rzeszutek Wilk, Hanweidong (Randy),
	Yanqiangjun, Luonengjun, qemu-devel, Fabio Fantoni, Gaowei (UVP),
	anthony.perard, Stefano Stabellini, Huangweidong (Hardware)

http://lists.xen.org/archives/html/xen-devel/2013-09/msg03113.html
As said above, In Xen platform, after using upstream qemu, all pci devices can be unpluged in the windows guest.
In this situation, the windows guest may occur blue screen when VM' user click the icon of pass-through Graphics card for trying to unplug the device.

The kvm system doesn't have this problem for the use of seabios.
http://www.seabios.org/pipermail/seabios/2011-September/002293.html
The patch above in seabios solves the problem. The patch is ported in hvmloader and works well.

This is done by runtime patching:
- Rename _EJ0 methods for PCI slots in DSDT to EJ0_:
  note that this has the same checksum, but
  is ignored by OSPM.
- At compile time, look for these methods in ASL source,
  find the matching AML, and store the offsets of these methods
  in a table named aml_ej0_data.
- At run time, go over aml_ej0_data, check which slots 
  not support hotplug and patch the ACPI table, replacing _EJ0 with EJ0_.

The files *.py are from seabios
diff -urN hvmloader/acpi/Makefile hvmloader_new//acpi/Makefile
--- hvmloader/acpi/Makefile	2013-10-16 11:51:53.000000000 +0800
+++ hvmloader_new//acpi/Makefile	2013-10-16 11:51:58.000000000 +0800
@@ -36,18 +36,34 @@
 
 dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
 	awk 'NR > 1 {print s} {s=$$0}' $< > $@
-	./mk_dsdt --dm-version qemu-xen >> $@
+	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@
+	./mk_dsdt --dm-version qemu-xen >> $@	
+	sed -i 's/aml_ej0_name/dsdt_anycpu_qemu_xen_aml_ej0_name/g' $@
+	sed -i 's/aml_adr_dword/dsdt_anycpu_qemu_xen_aml_adr_dword/g' $@
 
 # NB. awk invocation is a portable alternative to 'head -n -1'
 dsdt_%cpu.asl: dsdt.asl mk_dsdt
 	awk 'NR > 1 {print s} {s=$$0}' $< > $@
+	sed -i 's/AmlCode/dsdt_$*cpu/g' $@
 	./mk_dsdt --maxcpu $*  >> $@
 
 $(filter dsdt_%.c,$(C_SRC)): %.c: iasl %.asl
-	iasl -vs -p $* -tc $*.asl
-	sed -e 's/AmlCode/$*/g' $*.hex >$@
+	cpp -P $*.asl > $*.asl.i.orig
+	/usr/bin/python ../tools/acpi_extract_preprocess.py $*.asl.i.orig > $*.asl.i
+	iasl -vs -l -tc -p $* $*.asl.i
+	/usr/bin/python ../tools/acpi_extract.py $*.lst > $@
 	echo "int $*_len=sizeof($*);" >>$@
-	rm -f $*.aml $*.hex
+	rm -f $*.aml $*.hex $*.asl.i.orig $*.asl.i $*.lst
+
+dsdt_anycpu_qemu_xen.c:iasl dsdt_anycpu_qemu_xen.asl
+	cpp -P $*.asl > $*.asl.i.orig
+	/usr/bin/python ../tools/acpi_extract_preprocess.py $*.asl.i.orig > $*.asl.i
+	iasl -vs -l -tc -p $* $*.asl.i
+	/usr/bin/python ../tools/acpi_extract.py $*.lst > $@
+	echo "int $*_len=sizeof($*);" >>$@
+	echo "int $*_aml_ej0_name_len=sizeof($*_aml_ej0_name);" >>$@
+	echo "int $*_aml_adr_dword_len=sizeof($*_aml_adr_dword);" >>$@
+	rm -f $*.aml $*.hex $*.asl.i.orig $*.asl.i $*.lst
 
 iasl:
 	@echo
@@ -64,7 +80,7 @@
 
 clean:
 	rm -rf *.a *.o $(IASL_VER) $(IASL_VER).tar.gz $(DEPS)
-	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl
+	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl *.asl.i *.asl.i.orig *.lst
 
 install: all
 
diff -urN hvmloader/acpi/acpi2_0.h hvmloader_new//acpi/acpi2_0.h
--- hvmloader/acpi/acpi2_0.h	2013-10-16 11:54:49.000000000 +0800
+++ hvmloader_new//acpi/acpi2_0.h	2013-10-16 11:46:52.000000000 +0800
@@ -396,6 +396,11 @@
     int dsdt_anycpu_len;
     unsigned char *dsdt_15cpu;
     int dsdt_15cpu_len;
+    unsigned short *aml_ej0_name;
+    unsigned short *aml_adr_dword;
+    int aml_ej0_name_len;
+    int aml_adr_dword_len;
+    
 };
 
 void acpi_build_tables(struct acpi_config *config, unsigned int physical);
diff -urN hvmloader/acpi/build.c hvmloader_new//acpi/build.c
--- hvmloader/acpi/build.c	2013-10-16 11:55:55.000000000 +0800
+++ hvmloader_new//acpi/build.c	2013-10-16 11:46:52.000000000 +0800
@@ -30,6 +30,9 @@
 #define align16(sz)        (((sz) + 15) & ~15)
 #define fixed_strcpy(d, s) strncpy((d), (s), sizeof(d))
 
+
+#define PCI_RMV_BASE 0xae0c
+
 extern struct acpi_20_rsdp Rsdp;
 extern struct acpi_20_rsdt Rsdt;
 extern struct acpi_20_xsdt Xsdt;
@@ -404,6 +407,7 @@
     unsigned char       *dsdt;
     unsigned long        secondary_tables[ACPI_MAX_SECONDARY_TABLES];
     int                  nr_secondaries, i;
+    unsigned int rmvc_pcrm = 0;
 
     /* Allocate and initialise the acpi info area. */
     mem_hole_populate_ram(ACPI_INFO_PHYSICAL_ADDRESS >> PAGE_SHIFT, 1);
@@ -438,9 +442,26 @@
         dsdt = mem_alloc(config->dsdt_anycpu_len, 16);
         if (!dsdt) goto oom;
         memcpy(dsdt, config->dsdt_anycpu, config->dsdt_anycpu_len);
-        nr_processor_objects = HVM_MAX_VCPUS;
+    if(config->aml_adr_dword_len && config->aml_ej0_name_len &&
+        (config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]) == config->aml_ej0_name_len/sizeof(config->aml_ej0_name[0])))
+    {
+         rmvc_pcrm = inl(PCI_RMV_BASE); 
+	  printf("rmvc_pcrm is %x\n", rmvc_pcrm);
+        for(i = 0;  i < config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]); i ++)
+        {
+            /* Slot is in byte 2 in _ADR */
+            unsigned char slot = dsdt[config->aml_adr_dword[i] + 2] & 0x1F;
+            /* Sanity check */
+            if (memcmp(dsdt + config->aml_ej0_name[i], "_EJ0", 4)) {
+                goto oom;
+            }
+            if (!(rmvc_pcrm & (0x1 << slot))) {
+                memcpy(dsdt + config->aml_ej0_name[i], "EJ0_", 4);
+            }
+        }
     }
 
+    nr_processor_objects = HVM_MAX_VCPUS;
     /*
      * N.B. ACPI 1.0 operating systems may not handle FADT with revision 2
      * or above properly, notably Windows 2000, which tries to copy FADT
diff -urN hvmloader/acpi/dsdt.asl hvmloader_new//acpi/dsdt.asl
--- hvmloader/acpi/dsdt.asl	2013-10-16 11:56:20.000000000 +0800
+++ hvmloader_new//acpi/dsdt.asl	2013-10-16 11:46:52.000000000 +0800
@@ -16,6 +16,7 @@
  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  * Place - Suite 330, Boston, MA 02111-1307 USA.
  */
+ACPI_EXTRACT_ALL_CODE AmlCode
 
 DefinitionBlock ("DSDT.aml", "DSDT", 2, "Xen", "HVM", 0)
 {
diff -urN hvmloader/acpi/mk_dsdt.c hvmloader_new//acpi/mk_dsdt.c
--- hvmloader/acpi/mk_dsdt.c	2013-10-16 11:56:32.000000000 +0800
+++ hvmloader_new//acpi/mk_dsdt.c	2013-10-16 11:46:52.000000000 +0800
@@ -368,7 +368,9 @@
         /* hotplug_slot */
         for (slot = 1; slot <= 31; slot++) {
             push_block("Device", "S%i", slot); {
+                printf("ACPI_EXTRACT_NAME_DWORD_CONST aml_adr_dword\n");
                 stmt("Name", "_ADR, %#06x0000", slot);
+                printf("ACPI_EXTRACT_METHOD_STRING aml_ej0_name\n");
                 push_block("Method", "_EJ0,1"); {
                     stmt("Store", "ShiftLeft(1, %#06x), B0EJ", slot);
                     stmt("Return", "0x0");
@@ -453,7 +455,7 @@
 /*
  * Local variables:
  * mode: C
- * c-file-style: "BSD"
+ * c-set-style: "BSD"
  * c-basic-offset: 4
  * tab-width: 4
  * indent-tabs-mode: nil
diff -urN hvmloader/ovmf.c hvmloader_new//ovmf.c
--- hvmloader/ovmf.c	2013-10-16 11:57:15.000000000 +0800
+++ hvmloader_new//ovmf.c	2013-10-16 11:57:48.000000000 +0800
@@ -79,7 +79,11 @@
         .dsdt_anycpu = dsdt_anycpu,
         .dsdt_anycpu_len = dsdt_anycpu_len,
         .dsdt_15cpu = NULL, 
-        .dsdt_15cpu_len = 0
+        .dsdt_15cpu_len = 0,
+        .aml_ej0_name = NULL,
+        .aml_adr_dword = NULL,
+        .aml_ej0_name_len = 0,
+        .aml_adr_dword_len = 0,
     };
 
     acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
diff -urN hvmloader/rombios.c hvmloader_new//rombios.c
--- hvmloader/rombios.c	2013-10-16 11:57:15.000000000 +0800
+++ hvmloader_new//rombios.c	2013-10-16 11:57:48.000000000 +0800
@@ -179,6 +179,10 @@
         .dsdt_anycpu_len = dsdt_anycpu_len,
         .dsdt_15cpu = dsdt_15cpu,
         .dsdt_15cpu_len = dsdt_15cpu_len,
+        .aml_ej0_name = NULL,
+        .aml_adr_dword = NULL,
+        .aml_ej0_name_len = 0,
+        .aml_adr_dword_len = 0,
     };
 
     acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
diff -urN hvmloader/seabios.c hvmloader_new//seabios.c
--- hvmloader/seabios.c	2013-10-16 11:57:15.000000000 +0800
+++ hvmloader_new//seabios.c	2013-10-16 11:57:48.000000000 +0800
@@ -33,6 +33,10 @@
 
 extern unsigned char dsdt_anycpu_qemu_xen[];
 extern int dsdt_anycpu_qemu_xen_len;
+extern unsigned short dsdt_anycpu_qemu_xen_aml_ej0_name[];
+extern unsigned short dsdt_anycpu_qemu_xen_aml_adr_dword[];
+extern int dsdt_anycpu_qemu_xen_aml_ej0_name_len;
+extern int dsdt_anycpu_qemu_xen_aml_adr_dword_len;
 
 struct seabios_info {
     char signature[14]; /* XenHVMSeaBIOS\0 */
@@ -99,6 +103,10 @@
         .dsdt_anycpu_len = dsdt_anycpu_qemu_xen_len,
         .dsdt_15cpu = NULL,
         .dsdt_15cpu_len = 0,
+        .aml_ej0_name = dsdt_anycpu_qemu_xen_aml_ej0_name,
+        .aml_adr_dword = dsdt_anycpu_qemu_xen_aml_adr_dword,
+        .aml_ej0_name_len = dsdt_anycpu_qemu_xen_aml_ej0_name_len,
+        .aml_adr_dword_len = dsdt_anycpu_qemu_xen_aml_adr_dword_len,
     };
 
     acpi_build_tables(&config, rsdp);
diff -urN hvmloader/tools/acpi_extract.py hvmloader_new//tools/acpi_extract.py
--- hvmloader/tools/acpi_extract.py	1970-01-01 08:00:00.000000000 +0800
+++ hvmloader_new//tools/acpi_extract.py	2013-10-16 11:46:52.000000000 +0800
@@ -0,0 +1,308 @@
+#!/usr/bin/python
+# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+# Process mixed ASL/AML listing (.lst file) produced by iasl -l
+# Locate and execute ACPI_EXTRACT directives, output offset info
+# 
+# Documentation of ACPI_EXTRACT_* directive tags:
+# 
+# These directive tags output offset information from AML for BIOS runtime
+# table generation.
+# Each directive is of the form:
+# ACPI_EXTRACT_<TYPE> <array_name> <Operator> (...)
+# and causes the extractor to create an array
+# named <array_name> with offset, in the generated AML,
+# of an object of a given type in the following <Operator>.
+# 
+# A directive must fit on a single code line.
+# 
+# Object type in AML is verified, a mismatch causes a build failure.
+# 
+# Directives and operators currently supported are:
+# ACPI_EXTRACT_NAME_DWORD_CONST - extract a Dword Const object from Name()
+# ACPI_EXTRACT_NAME_WORD_CONST - extract a Word Const object from Name()
+# ACPI_EXTRACT_NAME_BYTE_CONST - extract a Byte Const object from Name()
+# ACPI_EXTRACT_METHOD_STRING - extract a NameString from Method()
+# ACPI_EXTRACT_NAME_STRING - extract a NameString from Name()
+# ACPI_EXTRACT_PROCESSOR_START - start of Processor() block
+# ACPI_EXTRACT_PROCESSOR_STRING - extract a NameString from Processor()
+# ACPI_EXTRACT_PROCESSOR_END - offset at last byte of Processor() + 1
+# ACPI_EXTRACT_PKG_START - start of Package block
+#
+# ACPI_EXTRACT_ALL_CODE - create an array storing the generated AML bytecode
+# 
+# ACPI_EXTRACT is not allowed anywhere else in code, except in comments.
+
+import re;
+import sys;
+import fileinput;
+
+aml = []
+asl = []
+output = {}
+debug = ""
+
+class asl_line:
+    line = None
+    lineno = None
+    aml_offset = None
+
+def die(diag):
+    sys.stderr.write("Error: %s; %s\n" % (diag, debug))
+    sys.exit(1)
+    
+#Store an ASL command, matching AML offset, and input line (for debugging)
+def add_asl(lineno, line):
+    l = asl_line()
+    l.line = line
+    l.lineno = lineno
+    l.aml_offset = len(aml)
+    asl.append(l)
+
+#Store an AML byte sequence
+#Verify that offset output by iasl matches # of bytes so far
+def add_aml(offset, line):
+    o = int(offset, 16);
+    # Sanity check: offset must match size of code so far
+    if (o != len(aml)):
+        die("Offset 0x%x != 0x%x" % (o, len(aml)))
+    # Strip any trailing dots and ASCII dump after "
+    line = re.sub(r'\s*\.*\s*".*$',"", line)
+    # Strip traling whitespace
+    line = re.sub(r'\s+$',"", line)
+    # Strip leading whitespace
+    line = re.sub(r'^\s+',"", line)
+    # Split on whitespace
+    code = re.split(r'\s+', line)
+    for c in code:
+        # Require a legal hex number, two digits
+        if (not(re.search(r'^[0-9A-Fa-f][0-9A-Fa-f]$', c))):
+            die("Unexpected octet %s" % c);
+        aml.append(int(c, 16));
+
+# Process aml bytecode array, decoding AML
+def aml_pkglen_bytes(offset):
+    # PkgLength can be multibyte. Bits 8-7 give the # of extra bytes.
+    pkglenbytes = aml[offset] >> 6;
+    return pkglenbytes + 1
+
+def aml_pkglen(offset):
+    pkgstart = offset
+    pkglenbytes = aml_pkglen_bytes(offset)
+    pkglen = aml[offset] & 0x3F
+    # If multibyte, first nibble only uses bits 0-3
+    if ((pkglenbytes > 0) and (pkglen & 0x30)):
+        die("PkgLen bytes 0x%x but first nibble 0x%x expected 0x0X" %
+            (pkglen, pkglen))
+    offset += 1
+    pkglenbytes -= 1
+    for i in range(pkglenbytes):
+        pkglen |= aml[offset + i] << (i * 8 + 4)
+    if (len(aml) < pkgstart + pkglen):
+        die("PckgLen 0x%x at offset 0x%x exceeds AML size 0x%x" %
+            (pkglen, offset, len(aml)))
+    return pkglen
+
+# Given method offset, find its NameString offset
+def aml_method_string(offset):
+    #0x14 MethodOp PkgLength NameString MethodFlags TermList
+    if (aml[offset] != 0x14):
+        die( "Method offset 0x%x: expected 0x14 actual 0x%x" %
+             (offset, aml[offset]));
+    offset += 1;
+    pkglenbytes = aml_pkglen_bytes(offset)
+    offset += pkglenbytes;
+    return offset;
+
+# Given name offset, find its NameString offset
+def aml_name_string(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x08):
+        die( "Name offset 0x%x: expected 0x08 actual 0x%x" %
+             (offset, aml[offset]));
+    offset += 1
+    # Block Name Modifier. Skip it.
+    if (aml[offset] == 0x5c or aml[offset] == 0x5e):
+        offset += 1
+    return offset;
+
+# Given data offset, find dword const offset
+def aml_data_dword_const(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x0C):
+        die( "Name offset 0x%x: expected 0x0C actual 0x%x" %
+             (offset, aml[offset]));
+    return offset + 1;
+
+# Given data offset, find word const offset
+def aml_data_word_const(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x0B):
+        die( "Name offset 0x%x: expected 0x0B actual 0x%x" %
+             (offset, aml[offset]));
+    return offset + 1;
+
+# Given data offset, find byte const offset
+def aml_data_byte_const(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x0A):
+        die( "Name offset 0x%x: expected 0x0A actual 0x%x" %
+             (offset, aml[offset]));
+    return offset + 1;
+
+# Given name offset, find dword const offset
+def aml_name_dword_const(offset):
+    return aml_data_dword_const(aml_name_string(offset) + 4)
+
+# Given name offset, find word const offset
+def aml_name_word_const(offset):
+    return aml_data_word_const(aml_name_string(offset) + 4)
+
+# Given name offset, find byte const offset
+def aml_name_byte_const(offset):
+    return aml_data_byte_const(aml_name_string(offset) + 4)
+
+def aml_processor_start(offset):
+    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
+    if ((aml[offset] != 0x5B) or (aml[offset + 1] != 0x83)):
+        die( "Name offset 0x%x: expected 0x5B 0x83 actual 0x%x 0x%x" %
+             (offset, aml[offset], aml[offset + 1]));
+    return offset
+
+def aml_processor_string(offset):
+    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
+    start = aml_processor_start(offset)
+    offset += 2
+    pkglenbytes = aml_pkglen_bytes(offset)
+    offset += pkglenbytes
+    return offset
+
+def aml_processor_end(offset):
+    start = aml_processor_start(offset)
+    offset += 2
+    pkglenbytes = aml_pkglen_bytes(offset)
+    pkglen = aml_pkglen(offset)
+    return offset + pkglen
+
+def aml_package_start(offset):
+    offset = aml_name_string(offset) + 4
+    # 0x12 PkgLength NumElements PackageElementList
+    if (aml[offset] != 0x12):
+        die( "Name offset 0x%x: expected 0x12 actual 0x%x" %
+             (offset, aml[offset]));
+    offset += 1
+    return offset + aml_pkglen_bytes(offset) + 1
+
+lineno = 0
+for line in fileinput.input():
+    # Strip trailing newline
+    line = line.rstrip();
+    # line number and debug string to output in case of errors
+    lineno = lineno + 1
+    debug = "input line %d: %s" % (lineno, line)
+    #ASL listing: space, then line#, then ...., then code
+    pasl = re.compile('^\s+([0-9]+)\.\.\.\.\s*')
+    m = pasl.search(line)
+    if (m):
+        add_asl(lineno, pasl.sub("", line));
+    # AML listing: offset in hex, then ...., then code
+    paml = re.compile('^([0-9A-Fa-f]+)\.\.\.\.\s*')
+    m = paml.search(line)
+    if (m):
+        add_aml(m.group(1), paml.sub("", line))
+
+# Now go over code
+# Track AML offset of a previous non-empty ASL command
+prev_aml_offset = -1
+for i in range(len(asl)):
+    debug = "input line %d: %s" % (asl[i].lineno, asl[i].line)
+
+    l = asl[i].line
+
+    # skip if not an extract directive
+    a = len(re.findall(r'ACPI_EXTRACT', l))
+    if (not a):
+        # If not empty, store AML offset. Will be used for sanity checks
+        # IASL seems to put {}. at random places in the listing.
+        # Ignore any non-words for the purpose of this test.
+        m = re.search(r'\w+', l)
+        if (m):
+                prev_aml_offset = asl[i].aml_offset
+        continue
+
+    if (a > 1):
+        die("Expected at most one ACPI_EXTRACT per line, actual %d" % a)
+
+    mext = re.search(r'''
+                      ^\s* # leading whitespace
+                      /\*\s* # start C comment
+                      (ACPI_EXTRACT_\w+) # directive: group(1)
+                      \s+ # whitspace separates directive from array name
+                      (\w+) # array name: group(2)
+                      \s*\*/ # end of C comment
+                      \s*$ # trailing whitespace
+                      ''', l, re.VERBOSE)
+    if (not mext):
+        die("Stray ACPI_EXTRACT in input")
+
+    # previous command must have produced some AML,
+    # otherwise we are in a middle of a block
+    if (prev_aml_offset == asl[i].aml_offset):
+        die("ACPI_EXTRACT directive in the middle of a block")
+
+    directive = mext.group(1)
+    array = mext.group(2)
+    offset = asl[i].aml_offset
+
+    if (directive == "ACPI_EXTRACT_ALL_CODE"):
+        if array in output:
+            die("%s directive used more than once" % directive)
+        output[array] = aml
+        continue
+    if (directive == "ACPI_EXTRACT_NAME_DWORD_CONST"):
+        offset = aml_name_dword_const(offset)
+    elif (directive == "ACPI_EXTRACT_NAME_WORD_CONST"):
+        offset = aml_name_word_const(offset)
+    elif (directive == "ACPI_EXTRACT_NAME_BYTE_CONST"):
+        offset = aml_name_byte_const(offset)
+    elif (directive == "ACPI_EXTRACT_NAME_STRING"):
+        offset = aml_name_string(offset)
+    elif (directive == "ACPI_EXTRACT_METHOD_STRING"):
+        offset = aml_method_string(offset)
+    elif (directive == "ACPI_EXTRACT_PROCESSOR_START"):
+        offset = aml_processor_start(offset)
+    elif (directive == "ACPI_EXTRACT_PROCESSOR_STRING"):
+        offset = aml_processor_string(offset)
+    elif (directive == "ACPI_EXTRACT_PROCESSOR_END"):
+        offset = aml_processor_end(offset)
+    elif (directive == "ACPI_EXTRACT_PKG_START"):
+        offset = aml_package_start(offset)
+    else:
+        die("Unsupported directive %s" % directive)
+
+    if array not in output:
+        output[array] = []
+    output[array].append(offset)
+
+debug = "at end of file"
+
+def get_value_type(maxvalue):
+    #Use type large enough to fit the table
+    if (maxvalue >= 0x10000):
+            return "int"
+    elif (maxvalue >= 0x100):
+            return "short"
+    else:
+            return "char"
+
+# Pretty print output
+for array in output.keys():
+    otype = get_value_type(max(output[array]))
+    odata = []
+    for value in output[array]:
+        odata.append("0x%x" % value)
+    sys.stdout.write("unsigned %s %s[] = {\n" % (otype, array))
+    sys.stdout.write(",\n".join(odata))
+    sys.stdout.write('\n};\n');
diff -urN hvmloader/tools/acpi_extract_preprocess.py hvmloader_new//tools/acpi_extract_preprocess.py
--- hvmloader/tools/acpi_extract_preprocess.py	1970-01-01 08:00:00.000000000 +0800
+++ hvmloader_new//tools/acpi_extract_preprocess.py	2013-10-16 11:46:53.000000000 +0800
@@ -0,0 +1,41 @@
+#!/usr/bin/python
+# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+# Read a preprocessed ASL listing and put each ACPI_EXTRACT
+# directive in a comment, to make iasl skip it.
+# We also put each directive on a new line, the machinery
+# in tools/acpi_extract.py requires this.
+
+import re;
+import sys;
+import fileinput;
+
+def die(diag):
+    sys.stderr.write("Error: %s\n" % (diag))
+    sys.exit(1)
+
+# Note: () around pattern make split return matched string as part of list
+psplit = re.compile(r''' (
+                          \b # At word boundary
+                          ACPI_EXTRACT_\w+ # directive
+                          \s+ # some whitespace
+                          \w+ # array name
+                         )''', re.VERBOSE);
+
+lineno = 0
+for line in fileinput.input():
+    # line number and debug string to output in case of errors
+    lineno = lineno + 1
+    debug = "input line %d: %s" % (lineno, line.rstrip())
+
+    s = psplit.split(line);
+    # The way split works, each odd item is the matching ACPI_EXTRACT directive.
+    # Put each in a comment, and on a line by itself.
+    for i in range(len(s)):
+        if (i % 2):
+            sys.stdout.write("\n/* %s */\n" % s[i])
+        else:
+            sys.stdout.write(s[i])
+

Best regards,
-Gonglei

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
  2013-10-16  6:30 [Qemu-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching Gonglei (Arei)
  2013-10-16  9:13 ` Fabio Fantoni
@ 2013-10-16  9:13 ` Fabio Fantoni
  2013-10-16  9:19 ` Ian Campbell
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 38+ messages in thread
From: Fabio Fantoni @ 2013-10-16  9:13 UTC (permalink / raw)
  To: Gonglei (Arei), xen-devel
  Cc: Yanqiangjun, Konrad Rzeszutek Wilk, Stefano Stabellini,
	Hanweidong (Randy),
	Luonengjun, qemu-devel, anthony.perard, Gaowei (UVP),
	Huangweidong (Hardware)

Il 16/10/2013 08:30, Gonglei (Arei) ha scritto:
> http://lists.xen.org/archives/html/xen-devel/2013-09/msg03113.html
> As said above, In Xen platform, after using upstream qemu, all pci devices can be unpluged in the windows guest.
> In this situation, the windows guest may occur blue screen when VM' user click the icon of pass-through Graphics card for trying to unplug the device.
>
> The kvm system doesn't have this problem for the use of seabios.
> http://www.seabios.org/pipermail/seabios/2011-September/002293.html
> The patch above in seabios solves the problem. The patch is ported in hvmloader and works well.

Thanks, I tried it but it fails to compile:
> /mnt/vm/xen/Xen/tools/firmware/hvmloader# make
> make[1]: Entering directory `/mnt/vm/xen/Xen/tools/firmware/hvmloader'
> make -C acpi all
> make[2]: Entering directory 
> `/mnt/vm/xen/Xen/tools/firmware/hvmloader/acpi'
> Makefile:59: warning: overriding commands for target 
> `dsdt_anycpu_qemu_xen.c'
> Makefile:51: warning: ignoring old commands for target 
> `dsdt_anycpu_qemu_xen.c'
> gcc   -O1 -fno-omit-frame-pointer -m32 -march=i686 -g 
> -fno-strict-aliasing -std=gnu99 -Wall -Wstrict-prototypes 
> -Wdeclaration-after-statement -Wno-unused-but-set-variable 
> -Wno-unused-local-typedefs   -D__XEN_TOOLS__ -MMD -MF .build.o.d 
> -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -fno-optimize-sibling-calls 
> -mno-tls-direct-seg-refs  -Werror -fno-stack-protector -fno-exceptions 
> -fno-builtin -msoft-float 
> -I/mnt/vm/xen/Xen/tools/firmware/hvmloader/acpi/../../../../tools/include 
> -c -o build.o build.c
> build.c: In function âacpi_build_tablesâ:
> build.c:555:1: error: expected declaration or statement at end of input
> make[2]: *** [build.o] Error 1
> make[2]: Leaving directory `/mnt/vm/xen/Xen/tools/firmware/hvmloader/acpi'
> make[1]: *** [subdir-all-acpi] Error 2
> make[1]: Leaving directory `/mnt/vm/xen/Xen/tools/firmware/hvmloader'
> make: *** [subdirs-all] Error 2

It seems there is something incomplete.

Here are the details of dom0 where I test it:
http://lists.xen.org/archives/html/xen-devel/2013-10/msg01111.html


>
> This is done by runtime patching:
> - Rename _EJ0 methods for PCI slots in DSDT to EJ0_:
>    note that this has the same checksum, but
>    is ignored by OSPM.
> - At compile time, look for these methods in ASL source,
>    find the matching AML, and store the offsets of these methods
>    in a table named aml_ej0_data.
> - At run time, go over aml_ej0_data, check which slots
>    not support hotplug and patch the ACPI table, replacing _EJ0 with EJ0_.
>
> The files *.py are from seabios
> diff -urN hvmloader/acpi/Makefile hvmloader_new//acpi/Makefile
> --- hvmloader/acpi/Makefile	2013-10-16 11:51:53.000000000 +0800
> +++ hvmloader_new//acpi/Makefile	2013-10-16 11:51:58.000000000 +0800
> @@ -36,18 +36,34 @@
>   
>   dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
>   	awk 'NR > 1 {print s} {s=$$0}' $< > $@
> -	./mk_dsdt --dm-version qemu-xen >> $@
> +	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@
> +	./mk_dsdt --dm-version qemu-xen >> $@	
> +	sed -i 's/aml_ej0_name/dsdt_anycpu_qemu_xen_aml_ej0_name/g' $@
> +	sed -i 's/aml_adr_dword/dsdt_anycpu_qemu_xen_aml_adr_dword/g' $@
>   
>   # NB. awk invocation is a portable alternative to 'head -n -1'
>   dsdt_%cpu.asl: dsdt.asl mk_dsdt
>   	awk 'NR > 1 {print s} {s=$$0}' $< > $@
> +	sed -i 's/AmlCode/dsdt_$*cpu/g' $@
>   	./mk_dsdt --maxcpu $*  >> $@
>   
>   $(filter dsdt_%.c,$(C_SRC)): %.c: iasl %.asl
> -	iasl -vs -p $* -tc $*.asl
> -	sed -e 's/AmlCode/$*/g' $*.hex >$@
> +	cpp -P $*.asl > $*.asl.i.orig
> +	/usr/bin/python ../tools/acpi_extract_preprocess.py $*.asl.i.orig > $*.asl.i
> +	iasl -vs -l -tc -p $* $*.asl.i
> +	/usr/bin/python ../tools/acpi_extract.py $*.lst > $@
>   	echo "int $*_len=sizeof($*);" >>$@
> -	rm -f $*.aml $*.hex
> +	rm -f $*.aml $*.hex $*.asl.i.orig $*.asl.i $*.lst
> +
> +dsdt_anycpu_qemu_xen.c:iasl dsdt_anycpu_qemu_xen.asl
> +	cpp -P $*.asl > $*.asl.i.orig
> +	/usr/bin/python ../tools/acpi_extract_preprocess.py $*.asl.i.orig > $*.asl.i
> +	iasl -vs -l -tc -p $* $*.asl.i
> +	/usr/bin/python ../tools/acpi_extract.py $*.lst > $@
> +	echo "int $*_len=sizeof($*);" >>$@
> +	echo "int $*_aml_ej0_name_len=sizeof($*_aml_ej0_name);" >>$@
> +	echo "int $*_aml_adr_dword_len=sizeof($*_aml_adr_dword);" >>$@
> +	rm -f $*.aml $*.hex $*.asl.i.orig $*.asl.i $*.lst
>   
>   iasl:
>   	@echo
> @@ -64,7 +80,7 @@
>   
>   clean:
>   	rm -rf *.a *.o $(IASL_VER) $(IASL_VER).tar.gz $(DEPS)
> -	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl
> +	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl *.asl.i *.asl.i.orig *.lst
>   
>   install: all
>   
> diff -urN hvmloader/acpi/acpi2_0.h hvmloader_new//acpi/acpi2_0.h
> --- hvmloader/acpi/acpi2_0.h	2013-10-16 11:54:49.000000000 +0800
> +++ hvmloader_new//acpi/acpi2_0.h	2013-10-16 11:46:52.000000000 +0800
> @@ -396,6 +396,11 @@
>       int dsdt_anycpu_len;
>       unsigned char *dsdt_15cpu;
>       int dsdt_15cpu_len;
> +    unsigned short *aml_ej0_name;
> +    unsigned short *aml_adr_dword;
> +    int aml_ej0_name_len;
> +    int aml_adr_dword_len;
> +
>   };
>   
>   void acpi_build_tables(struct acpi_config *config, unsigned int physical);
> diff -urN hvmloader/acpi/build.c hvmloader_new//acpi/build.c
> --- hvmloader/acpi/build.c	2013-10-16 11:55:55.000000000 +0800
> +++ hvmloader_new//acpi/build.c	2013-10-16 11:46:52.000000000 +0800
> @@ -30,6 +30,9 @@
>   #define align16(sz)        (((sz) + 15) & ~15)
>   #define fixed_strcpy(d, s) strncpy((d), (s), sizeof(d))
>   
> +
> +#define PCI_RMV_BASE 0xae0c
> +
>   extern struct acpi_20_rsdp Rsdp;
>   extern struct acpi_20_rsdt Rsdt;
>   extern struct acpi_20_xsdt Xsdt;
> @@ -404,6 +407,7 @@
>       unsigned char       *dsdt;
>       unsigned long        secondary_tables[ACPI_MAX_SECONDARY_TABLES];
>       int                  nr_secondaries, i;
> +    unsigned int rmvc_pcrm = 0;
>   
>       /* Allocate and initialise the acpi info area. */
>       mem_hole_populate_ram(ACPI_INFO_PHYSICAL_ADDRESS >> PAGE_SHIFT, 1);
> @@ -438,9 +442,26 @@
>           dsdt = mem_alloc(config->dsdt_anycpu_len, 16);
>           if (!dsdt) goto oom;
>           memcpy(dsdt, config->dsdt_anycpu, config->dsdt_anycpu_len);
> -        nr_processor_objects = HVM_MAX_VCPUS;
> +    if(config->aml_adr_dword_len && config->aml_ej0_name_len &&
> +        (config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]) == config->aml_ej0_name_len/sizeof(config->aml_ej0_name[0])))
> +    {
> +         rmvc_pcrm = inl(PCI_RMV_BASE);
> +	  printf("rmvc_pcrm is %x\n", rmvc_pcrm);
> +        for(i = 0;  i < config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]); i ++)
> +        {
> +            /* Slot is in byte 2 in _ADR */
> +            unsigned char slot = dsdt[config->aml_adr_dword[i] + 2] & 0x1F;
> +            /* Sanity check */
> +            if (memcmp(dsdt + config->aml_ej0_name[i], "_EJ0", 4)) {
> +                goto oom;
> +            }
> +            if (!(rmvc_pcrm & (0x1 << slot))) {
> +                memcpy(dsdt + config->aml_ej0_name[i], "EJ0_", 4);
> +            }
> +        }
>       }
>   
> +    nr_processor_objects = HVM_MAX_VCPUS;
>       /*
>        * N.B. ACPI 1.0 operating systems may not handle FADT with revision 2
>        * or above properly, notably Windows 2000, which tries to copy FADT
> diff -urN hvmloader/acpi/dsdt.asl hvmloader_new//acpi/dsdt.asl
> --- hvmloader/acpi/dsdt.asl	2013-10-16 11:56:20.000000000 +0800
> +++ hvmloader_new//acpi/dsdt.asl	2013-10-16 11:46:52.000000000 +0800
> @@ -16,6 +16,7 @@
>    * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
>    * Place - Suite 330, Boston, MA 02111-1307 USA.
>    */
> +ACPI_EXTRACT_ALL_CODE AmlCode
>   
>   DefinitionBlock ("DSDT.aml", "DSDT", 2, "Xen", "HVM", 0)
>   {
> diff -urN hvmloader/acpi/mk_dsdt.c hvmloader_new//acpi/mk_dsdt.c
> --- hvmloader/acpi/mk_dsdt.c	2013-10-16 11:56:32.000000000 +0800
> +++ hvmloader_new//acpi/mk_dsdt.c	2013-10-16 11:46:52.000000000 +0800
> @@ -368,7 +368,9 @@
>           /* hotplug_slot */
>           for (slot = 1; slot <= 31; slot++) {
>               push_block("Device", "S%i", slot); {
> +                printf("ACPI_EXTRACT_NAME_DWORD_CONST aml_adr_dword\n");
>                   stmt("Name", "_ADR, %#06x0000", slot);
> +                printf("ACPI_EXTRACT_METHOD_STRING aml_ej0_name\n");
>                   push_block("Method", "_EJ0,1"); {
>                       stmt("Store", "ShiftLeft(1, %#06x), B0EJ", slot);
>                       stmt("Return", "0x0");
> @@ -453,7 +455,7 @@
>   /*
>    * Local variables:
>    * mode: C
> - * c-file-style: "BSD"
> + * c-set-style: "BSD"
>    * c-basic-offset: 4
>    * tab-width: 4
>    * indent-tabs-mode: nil
> diff -urN hvmloader/ovmf.c hvmloader_new//ovmf.c
> --- hvmloader/ovmf.c	2013-10-16 11:57:15.000000000 +0800
> +++ hvmloader_new//ovmf.c	2013-10-16 11:57:48.000000000 +0800
> @@ -79,7 +79,11 @@
>           .dsdt_anycpu = dsdt_anycpu,
>           .dsdt_anycpu_len = dsdt_anycpu_len,
>           .dsdt_15cpu = NULL,
> -        .dsdt_15cpu_len = 0
> +        .dsdt_15cpu_len = 0,
> +        .aml_ej0_name = NULL,
> +        .aml_adr_dword = NULL,
> +        .aml_ej0_name_len = 0,
> +        .aml_adr_dword_len = 0,
>       };
>   
>       acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
> diff -urN hvmloader/rombios.c hvmloader_new//rombios.c
> --- hvmloader/rombios.c	2013-10-16 11:57:15.000000000 +0800
> +++ hvmloader_new//rombios.c	2013-10-16 11:57:48.000000000 +0800
> @@ -179,6 +179,10 @@
>           .dsdt_anycpu_len = dsdt_anycpu_len,
>           .dsdt_15cpu = dsdt_15cpu,
>           .dsdt_15cpu_len = dsdt_15cpu_len,
> +        .aml_ej0_name = NULL,
> +        .aml_adr_dword = NULL,
> +        .aml_ej0_name_len = 0,
> +        .aml_adr_dword_len = 0,
>       };
>   
>       acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
> diff -urN hvmloader/seabios.c hvmloader_new//seabios.c
> --- hvmloader/seabios.c	2013-10-16 11:57:15.000000000 +0800
> +++ hvmloader_new//seabios.c	2013-10-16 11:57:48.000000000 +0800
> @@ -33,6 +33,10 @@
>   
>   extern unsigned char dsdt_anycpu_qemu_xen[];
>   extern int dsdt_anycpu_qemu_xen_len;
> +extern unsigned short dsdt_anycpu_qemu_xen_aml_ej0_name[];
> +extern unsigned short dsdt_anycpu_qemu_xen_aml_adr_dword[];
> +extern int dsdt_anycpu_qemu_xen_aml_ej0_name_len;
> +extern int dsdt_anycpu_qemu_xen_aml_adr_dword_len;
>   
>   struct seabios_info {
>       char signature[14]; /* XenHVMSeaBIOS\0 */
> @@ -99,6 +103,10 @@
>           .dsdt_anycpu_len = dsdt_anycpu_qemu_xen_len,
>           .dsdt_15cpu = NULL,
>           .dsdt_15cpu_len = 0,
> +        .aml_ej0_name = dsdt_anycpu_qemu_xen_aml_ej0_name,
> +        .aml_adr_dword = dsdt_anycpu_qemu_xen_aml_adr_dword,
> +        .aml_ej0_name_len = dsdt_anycpu_qemu_xen_aml_ej0_name_len,
> +        .aml_adr_dword_len = dsdt_anycpu_qemu_xen_aml_adr_dword_len,
>       };
>   
>       acpi_build_tables(&config, rsdp);
> diff -urN hvmloader/tools/acpi_extract.py hvmloader_new//tools/acpi_extract.py
> --- hvmloader/tools/acpi_extract.py	1970-01-01 08:00:00.000000000 +0800
> +++ hvmloader_new//tools/acpi_extract.py	2013-10-16 11:46:52.000000000 +0800
> @@ -0,0 +1,308 @@
> +#!/usr/bin/python
> +# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin<mst@redhat.com>
> +#
> +# This file may be distributed under the terms of the GNU GPLv3 license.
> +
> +# Process mixed ASL/AML listing (.lst file) produced by iasl -l
> +# Locate and execute ACPI_EXTRACT directives, output offset info
> +#
> +# Documentation of ACPI_EXTRACT_* directive tags:
> +#
> +# These directive tags output offset information from AML for BIOS runtime
> +# table generation.
> +# Each directive is of the form:
> +# ACPI_EXTRACT_<TYPE> <array_name> <Operator> (...)
> +# and causes the extractor to create an array
> +# named <array_name> with offset, in the generated AML,
> +# of an object of a given type in the following <Operator>.
> +#
> +# A directive must fit on a single code line.
> +#
> +# Object type in AML is verified, a mismatch causes a build failure.
> +#
> +# Directives and operators currently supported are:
> +# ACPI_EXTRACT_NAME_DWORD_CONST - extract a Dword Const object from Name()
> +# ACPI_EXTRACT_NAME_WORD_CONST - extract a Word Const object from Name()
> +# ACPI_EXTRACT_NAME_BYTE_CONST - extract a Byte Const object from Name()
> +# ACPI_EXTRACT_METHOD_STRING - extract a NameString from Method()
> +# ACPI_EXTRACT_NAME_STRING - extract a NameString from Name()
> +# ACPI_EXTRACT_PROCESSOR_START - start of Processor() block
> +# ACPI_EXTRACT_PROCESSOR_STRING - extract a NameString from Processor()
> +# ACPI_EXTRACT_PROCESSOR_END - offset at last byte of Processor() + 1
> +# ACPI_EXTRACT_PKG_START - start of Package block
> +#
> +# ACPI_EXTRACT_ALL_CODE - create an array storing the generated AML bytecode
> +#
> +# ACPI_EXTRACT is not allowed anywhere else in code, except in comments.
> +
> +import re;
> +import sys;
> +import fileinput;
> +
> +aml = []
> +asl = []
> +output = {}
> +debug = ""
> +
> +class asl_line:
> +    line = None
> +    lineno = None
> +    aml_offset = None
> +
> +def die(diag):
> +    sys.stderr.write("Error: %s; %s\n" % (diag, debug))
> +    sys.exit(1)
> +
> +#Store an ASL command, matching AML offset, and input line (for debugging)
> +def add_asl(lineno, line):
> +    l = asl_line()
> +    l.line = line
> +    l.lineno = lineno
> +    l.aml_offset = len(aml)
> +    asl.append(l)
> +
> +#Store an AML byte sequence
> +#Verify that offset output by iasl matches # of bytes so far
> +def add_aml(offset, line):
> +    o = int(offset, 16);
> +    # Sanity check: offset must match size of code so far
> +    if (o != len(aml)):
> +        die("Offset 0x%x != 0x%x" % (o, len(aml)))
> +    # Strip any trailing dots and ASCII dump after "
> +    line = re.sub(r'\s*\.*\s*".*$',"", line)
> +    # Strip traling whitespace
> +    line = re.sub(r'\s+$',"", line)
> +    # Strip leading whitespace
> +    line = re.sub(r'^\s+',"", line)
> +    # Split on whitespace
> +    code = re.split(r'\s+', line)
> +    for c in code:
> +        # Require a legal hex number, two digits
> +        if (not(re.search(r'^[0-9A-Fa-f][0-9A-Fa-f]$', c))):
> +            die("Unexpected octet %s" % c);
> +        aml.append(int(c, 16));
> +
> +# Process aml bytecode array, decoding AML
> +def aml_pkglen_bytes(offset):
> +    # PkgLength can be multibyte. Bits 8-7 give the # of extra bytes.
> +    pkglenbytes = aml[offset] >> 6;
> +    return pkglenbytes + 1
> +
> +def aml_pkglen(offset):
> +    pkgstart = offset
> +    pkglenbytes = aml_pkglen_bytes(offset)
> +    pkglen = aml[offset] & 0x3F
> +    # If multibyte, first nibble only uses bits 0-3
> +    if ((pkglenbytes > 0) and (pkglen & 0x30)):
> +        die("PkgLen bytes 0x%x but first nibble 0x%x expected 0x0X" %
> +            (pkglen, pkglen))
> +    offset += 1
> +    pkglenbytes -= 1
> +    for i in range(pkglenbytes):
> +        pkglen |= aml[offset + i] << (i * 8 + 4)
> +    if (len(aml) < pkgstart + pkglen):
> +        die("PckgLen 0x%x at offset 0x%x exceeds AML size 0x%x" %
> +            (pkglen, offset, len(aml)))
> +    return pkglen
> +
> +# Given method offset, find its NameString offset
> +def aml_method_string(offset):
> +    #0x14 MethodOp PkgLength NameString MethodFlags TermList
> +    if (aml[offset] != 0x14):
> +        die( "Method offset 0x%x: expected 0x14 actual 0x%x" %
> +             (offset, aml[offset]));
> +    offset += 1;
> +    pkglenbytes = aml_pkglen_bytes(offset)
> +    offset += pkglenbytes;
> +    return offset;
> +
> +# Given name offset, find its NameString offset
> +def aml_name_string(offset):
> +    #0x08 NameOp NameString DataRef
> +    if (aml[offset] != 0x08):
> +        die( "Name offset 0x%x: expected 0x08 actual 0x%x" %
> +             (offset, aml[offset]));
> +    offset += 1
> +    # Block Name Modifier. Skip it.
> +    if (aml[offset] == 0x5c or aml[offset] == 0x5e):
> +        offset += 1
> +    return offset;
> +
> +# Given data offset, find dword const offset
> +def aml_data_dword_const(offset):
> +    #0x08 NameOp NameString DataRef
> +    if (aml[offset] != 0x0C):
> +        die( "Name offset 0x%x: expected 0x0C actual 0x%x" %
> +             (offset, aml[offset]));
> +    return offset + 1;
> +
> +# Given data offset, find word const offset
> +def aml_data_word_const(offset):
> +    #0x08 NameOp NameString DataRef
> +    if (aml[offset] != 0x0B):
> +        die( "Name offset 0x%x: expected 0x0B actual 0x%x" %
> +             (offset, aml[offset]));
> +    return offset + 1;
> +
> +# Given data offset, find byte const offset
> +def aml_data_byte_const(offset):
> +    #0x08 NameOp NameString DataRef
> +    if (aml[offset] != 0x0A):
> +        die( "Name offset 0x%x: expected 0x0A actual 0x%x" %
> +             (offset, aml[offset]));
> +    return offset + 1;
> +
> +# Given name offset, find dword const offset
> +def aml_name_dword_const(offset):
> +    return aml_data_dword_const(aml_name_string(offset) + 4)
> +
> +# Given name offset, find word const offset
> +def aml_name_word_const(offset):
> +    return aml_data_word_const(aml_name_string(offset) + 4)
> +
> +# Given name offset, find byte const offset
> +def aml_name_byte_const(offset):
> +    return aml_data_byte_const(aml_name_string(offset) + 4)
> +
> +def aml_processor_start(offset):
> +    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
> +    if ((aml[offset] != 0x5B) or (aml[offset + 1] != 0x83)):
> +        die( "Name offset 0x%x: expected 0x5B 0x83 actual 0x%x 0x%x" %
> +             (offset, aml[offset], aml[offset + 1]));
> +    return offset
> +
> +def aml_processor_string(offset):
> +    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
> +    start = aml_processor_start(offset)
> +    offset += 2
> +    pkglenbytes = aml_pkglen_bytes(offset)
> +    offset += pkglenbytes
> +    return offset
> +
> +def aml_processor_end(offset):
> +    start = aml_processor_start(offset)
> +    offset += 2
> +    pkglenbytes = aml_pkglen_bytes(offset)
> +    pkglen = aml_pkglen(offset)
> +    return offset + pkglen
> +
> +def aml_package_start(offset):
> +    offset = aml_name_string(offset) + 4
> +    # 0x12 PkgLength NumElements PackageElementList
> +    if (aml[offset] != 0x12):
> +        die( "Name offset 0x%x: expected 0x12 actual 0x%x" %
> +             (offset, aml[offset]));
> +    offset += 1
> +    return offset + aml_pkglen_bytes(offset) + 1
> +
> +lineno = 0
> +for line in fileinput.input():
> +    # Strip trailing newline
> +    line = line.rstrip();
> +    # line number and debug string to output in case of errors
> +    lineno = lineno + 1
> +    debug = "input line %d: %s" % (lineno, line)
> +    #ASL listing: space, then line#, then ...., then code
> +    pasl = re.compile('^\s+([0-9]+)\.\.\.\.\s*')
> +    m = pasl.search(line)
> +    if (m):
> +        add_asl(lineno, pasl.sub("", line));
> +    # AML listing: offset in hex, then ...., then code
> +    paml = re.compile('^([0-9A-Fa-f]+)\.\.\.\.\s*')
> +    m = paml.search(line)
> +    if (m):
> +        add_aml(m.group(1), paml.sub("", line))
> +
> +# Now go over code
> +# Track AML offset of a previous non-empty ASL command
> +prev_aml_offset = -1
> +for i in range(len(asl)):
> +    debug = "input line %d: %s" % (asl[i].lineno, asl[i].line)
> +
> +    l = asl[i].line
> +
> +    # skip if not an extract directive
> +    a = len(re.findall(r'ACPI_EXTRACT', l))
> +    if (not a):
> +        # If not empty, store AML offset. Will be used for sanity checks
> +        # IASL seems to put {}. at random places in the listing.
> +        # Ignore any non-words for the purpose of this test.
> +        m = re.search(r'\w+', l)
> +        if (m):
> +                prev_aml_offset = asl[i].aml_offset
> +        continue
> +
> +    if (a > 1):
> +        die("Expected at most one ACPI_EXTRACT per line, actual %d" % a)
> +
> +    mext = re.search(r'''
> +                      ^\s* # leading whitespace
> +                      /\*\s* # start C comment
> +                      (ACPI_EXTRACT_\w+) # directive: group(1)
> +                      \s+ # whitspace separates directive from array name
> +                      (\w+) # array name: group(2)
> +                      \s*\*/ # end of C comment
> +                      \s*$ # trailing whitespace
> +                      ''', l, re.VERBOSE)
> +    if (not mext):
> +        die("Stray ACPI_EXTRACT in input")
> +
> +    # previous command must have produced some AML,
> +    # otherwise we are in a middle of a block
> +    if (prev_aml_offset == asl[i].aml_offset):
> +        die("ACPI_EXTRACT directive in the middle of a block")
> +
> +    directive = mext.group(1)
> +    array = mext.group(2)
> +    offset = asl[i].aml_offset
> +
> +    if (directive == "ACPI_EXTRACT_ALL_CODE"):
> +        if array in output:
> +            die("%s directive used more than once" % directive)
> +        output[array] = aml
> +        continue
> +    if (directive == "ACPI_EXTRACT_NAME_DWORD_CONST"):
> +        offset = aml_name_dword_const(offset)
> +    elif (directive == "ACPI_EXTRACT_NAME_WORD_CONST"):
> +        offset = aml_name_word_const(offset)
> +    elif (directive == "ACPI_EXTRACT_NAME_BYTE_CONST"):
> +        offset = aml_name_byte_const(offset)
> +    elif (directive == "ACPI_EXTRACT_NAME_STRING"):
> +        offset = aml_name_string(offset)
> +    elif (directive == "ACPI_EXTRACT_METHOD_STRING"):
> +        offset = aml_method_string(offset)
> +    elif (directive == "ACPI_EXTRACT_PROCESSOR_START"):
> +        offset = aml_processor_start(offset)
> +    elif (directive == "ACPI_EXTRACT_PROCESSOR_STRING"):
> +        offset = aml_processor_string(offset)
> +    elif (directive == "ACPI_EXTRACT_PROCESSOR_END"):
> +        offset = aml_processor_end(offset)
> +    elif (directive == "ACPI_EXTRACT_PKG_START"):
> +        offset = aml_package_start(offset)
> +    else:
> +        die("Unsupported directive %s" % directive)
> +
> +    if array not in output:
> +        output[array] = []
> +    output[array].append(offset)
> +
> +debug = "at end of file"
> +
> +def get_value_type(maxvalue):
> +    #Use type large enough to fit the table
> +    if (maxvalue >= 0x10000):
> +            return "int"
> +    elif (maxvalue >= 0x100):
> +            return "short"
> +    else:
> +            return "char"
> +
> +# Pretty print output
> +for array in output.keys():
> +    otype = get_value_type(max(output[array]))
> +    odata = []
> +    for value in output[array]:
> +        odata.append("0x%x" % value)
> +    sys.stdout.write("unsigned %s %s[] = {\n" % (otype, array))
> +    sys.stdout.write(",\n".join(odata))
> +    sys.stdout.write('\n};\n');
> diff -urN hvmloader/tools/acpi_extract_preprocess.py hvmloader_new//tools/acpi_extract_preprocess.py
> --- hvmloader/tools/acpi_extract_preprocess.py	1970-01-01 08:00:00.000000000 +0800
> +++ hvmloader_new//tools/acpi_extract_preprocess.py	2013-10-16 11:46:53.000000000 +0800
> @@ -0,0 +1,41 @@
> +#!/usr/bin/python
> +# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin<mst@redhat.com>
> +#
> +# This file may be distributed under the terms of the GNU GPLv3 license.
> +
> +# Read a preprocessed ASL listing and put each ACPI_EXTRACT
> +# directive in a comment, to make iasl skip it.
> +# We also put each directive on a new line, the machinery
> +# in tools/acpi_extract.py requires this.
> +
> +import re;
> +import sys;
> +import fileinput;
> +
> +def die(diag):
> +    sys.stderr.write("Error: %s\n" % (diag))
> +    sys.exit(1)
> +
> +# Note: () around pattern make split return matched string as part of list
> +psplit = re.compile(r''' (
> +                          \b # At word boundary
> +                          ACPI_EXTRACT_\w+ # directive
> +                          \s+ # some whitespace
> +                          \w+ # array name
> +                         )''', re.VERBOSE);
> +
> +lineno = 0
> +for line in fileinput.input():
> +    # line number and debug string to output in case of errors
> +    lineno = lineno + 1
> +    debug = "input line %d: %s" % (lineno, line.rstrip())
> +
> +    s = psplit.split(line);
> +    # The way split works, each odd item is the matching ACPI_EXTRACT directive.
> +    # Put each in a comment, and on a line by itself.
> +    for i in range(len(s)):
> +        if (i % 2):
> +            sys.stdout.write("\n/* %s */\n" % s[i])
> +        else:
> +            sys.stdout.write(s[i])
> +

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
  2013-10-16  6:30 [Qemu-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching Gonglei (Arei)
@ 2013-10-16  9:13 ` Fabio Fantoni
  2013-10-16  9:13 ` [Qemu-devel] " Fabio Fantoni
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 38+ messages in thread
From: Fabio Fantoni @ 2013-10-16  9:13 UTC (permalink / raw)
  To: Gonglei (Arei), xen-devel
  Cc: Yanqiangjun, Stefano Stabellini, Hanweidong (Randy),
	Luonengjun, qemu-devel, anthony.perard, Gaowei (UVP),
	Huangweidong (Hardware)

Il 16/10/2013 08:30, Gonglei (Arei) ha scritto:
> http://lists.xen.org/archives/html/xen-devel/2013-09/msg03113.html
> As said above, In Xen platform, after using upstream qemu, all pci devices can be unpluged in the windows guest.
> In this situation, the windows guest may occur blue screen when VM' user click the icon of pass-through Graphics card for trying to unplug the device.
>
> The kvm system doesn't have this problem for the use of seabios.
> http://www.seabios.org/pipermail/seabios/2011-September/002293.html
> The patch above in seabios solves the problem. The patch is ported in hvmloader and works well.

Thanks, I tried it but it fails to compile:
> /mnt/vm/xen/Xen/tools/firmware/hvmloader# make
> make[1]: Entering directory `/mnt/vm/xen/Xen/tools/firmware/hvmloader'
> make -C acpi all
> make[2]: Entering directory 
> `/mnt/vm/xen/Xen/tools/firmware/hvmloader/acpi'
> Makefile:59: warning: overriding commands for target 
> `dsdt_anycpu_qemu_xen.c'
> Makefile:51: warning: ignoring old commands for target 
> `dsdt_anycpu_qemu_xen.c'
> gcc   -O1 -fno-omit-frame-pointer -m32 -march=i686 -g 
> -fno-strict-aliasing -std=gnu99 -Wall -Wstrict-prototypes 
> -Wdeclaration-after-statement -Wno-unused-but-set-variable 
> -Wno-unused-local-typedefs   -D__XEN_TOOLS__ -MMD -MF .build.o.d 
> -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -fno-optimize-sibling-calls 
> -mno-tls-direct-seg-refs  -Werror -fno-stack-protector -fno-exceptions 
> -fno-builtin -msoft-float 
> -I/mnt/vm/xen/Xen/tools/firmware/hvmloader/acpi/../../../../tools/include 
> -c -o build.o build.c
> build.c: In function âacpi_build_tablesâ:
> build.c:555:1: error: expected declaration or statement at end of input
> make[2]: *** [build.o] Error 1
> make[2]: Leaving directory `/mnt/vm/xen/Xen/tools/firmware/hvmloader/acpi'
> make[1]: *** [subdir-all-acpi] Error 2
> make[1]: Leaving directory `/mnt/vm/xen/Xen/tools/firmware/hvmloader'
> make: *** [subdirs-all] Error 2

It seems there is something incomplete.

Here are the details of dom0 where I test it:
http://lists.xen.org/archives/html/xen-devel/2013-10/msg01111.html


>
> This is done by runtime patching:
> - Rename _EJ0 methods for PCI slots in DSDT to EJ0_:
>    note that this has the same checksum, but
>    is ignored by OSPM.
> - At compile time, look for these methods in ASL source,
>    find the matching AML, and store the offsets of these methods
>    in a table named aml_ej0_data.
> - At run time, go over aml_ej0_data, check which slots
>    not support hotplug and patch the ACPI table, replacing _EJ0 with EJ0_.
>
> The files *.py are from seabios
> diff -urN hvmloader/acpi/Makefile hvmloader_new//acpi/Makefile
> --- hvmloader/acpi/Makefile	2013-10-16 11:51:53.000000000 +0800
> +++ hvmloader_new//acpi/Makefile	2013-10-16 11:51:58.000000000 +0800
> @@ -36,18 +36,34 @@
>   
>   dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
>   	awk 'NR > 1 {print s} {s=$$0}' $< > $@
> -	./mk_dsdt --dm-version qemu-xen >> $@
> +	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@
> +	./mk_dsdt --dm-version qemu-xen >> $@	
> +	sed -i 's/aml_ej0_name/dsdt_anycpu_qemu_xen_aml_ej0_name/g' $@
> +	sed -i 's/aml_adr_dword/dsdt_anycpu_qemu_xen_aml_adr_dword/g' $@
>   
>   # NB. awk invocation is a portable alternative to 'head -n -1'
>   dsdt_%cpu.asl: dsdt.asl mk_dsdt
>   	awk 'NR > 1 {print s} {s=$$0}' $< > $@
> +	sed -i 's/AmlCode/dsdt_$*cpu/g' $@
>   	./mk_dsdt --maxcpu $*  >> $@
>   
>   $(filter dsdt_%.c,$(C_SRC)): %.c: iasl %.asl
> -	iasl -vs -p $* -tc $*.asl
> -	sed -e 's/AmlCode/$*/g' $*.hex >$@
> +	cpp -P $*.asl > $*.asl.i.orig
> +	/usr/bin/python ../tools/acpi_extract_preprocess.py $*.asl.i.orig > $*.asl.i
> +	iasl -vs -l -tc -p $* $*.asl.i
> +	/usr/bin/python ../tools/acpi_extract.py $*.lst > $@
>   	echo "int $*_len=sizeof($*);" >>$@
> -	rm -f $*.aml $*.hex
> +	rm -f $*.aml $*.hex $*.asl.i.orig $*.asl.i $*.lst
> +
> +dsdt_anycpu_qemu_xen.c:iasl dsdt_anycpu_qemu_xen.asl
> +	cpp -P $*.asl > $*.asl.i.orig
> +	/usr/bin/python ../tools/acpi_extract_preprocess.py $*.asl.i.orig > $*.asl.i
> +	iasl -vs -l -tc -p $* $*.asl.i
> +	/usr/bin/python ../tools/acpi_extract.py $*.lst > $@
> +	echo "int $*_len=sizeof($*);" >>$@
> +	echo "int $*_aml_ej0_name_len=sizeof($*_aml_ej0_name);" >>$@
> +	echo "int $*_aml_adr_dword_len=sizeof($*_aml_adr_dword);" >>$@
> +	rm -f $*.aml $*.hex $*.asl.i.orig $*.asl.i $*.lst
>   
>   iasl:
>   	@echo
> @@ -64,7 +80,7 @@
>   
>   clean:
>   	rm -rf *.a *.o $(IASL_VER) $(IASL_VER).tar.gz $(DEPS)
> -	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl
> +	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl *.asl.i *.asl.i.orig *.lst
>   
>   install: all
>   
> diff -urN hvmloader/acpi/acpi2_0.h hvmloader_new//acpi/acpi2_0.h
> --- hvmloader/acpi/acpi2_0.h	2013-10-16 11:54:49.000000000 +0800
> +++ hvmloader_new//acpi/acpi2_0.h	2013-10-16 11:46:52.000000000 +0800
> @@ -396,6 +396,11 @@
>       int dsdt_anycpu_len;
>       unsigned char *dsdt_15cpu;
>       int dsdt_15cpu_len;
> +    unsigned short *aml_ej0_name;
> +    unsigned short *aml_adr_dword;
> +    int aml_ej0_name_len;
> +    int aml_adr_dword_len;
> +
>   };
>   
>   void acpi_build_tables(struct acpi_config *config, unsigned int physical);
> diff -urN hvmloader/acpi/build.c hvmloader_new//acpi/build.c
> --- hvmloader/acpi/build.c	2013-10-16 11:55:55.000000000 +0800
> +++ hvmloader_new//acpi/build.c	2013-10-16 11:46:52.000000000 +0800
> @@ -30,6 +30,9 @@
>   #define align16(sz)        (((sz) + 15) & ~15)
>   #define fixed_strcpy(d, s) strncpy((d), (s), sizeof(d))
>   
> +
> +#define PCI_RMV_BASE 0xae0c
> +
>   extern struct acpi_20_rsdp Rsdp;
>   extern struct acpi_20_rsdt Rsdt;
>   extern struct acpi_20_xsdt Xsdt;
> @@ -404,6 +407,7 @@
>       unsigned char       *dsdt;
>       unsigned long        secondary_tables[ACPI_MAX_SECONDARY_TABLES];
>       int                  nr_secondaries, i;
> +    unsigned int rmvc_pcrm = 0;
>   
>       /* Allocate and initialise the acpi info area. */
>       mem_hole_populate_ram(ACPI_INFO_PHYSICAL_ADDRESS >> PAGE_SHIFT, 1);
> @@ -438,9 +442,26 @@
>           dsdt = mem_alloc(config->dsdt_anycpu_len, 16);
>           if (!dsdt) goto oom;
>           memcpy(dsdt, config->dsdt_anycpu, config->dsdt_anycpu_len);
> -        nr_processor_objects = HVM_MAX_VCPUS;
> +    if(config->aml_adr_dword_len && config->aml_ej0_name_len &&
> +        (config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]) == config->aml_ej0_name_len/sizeof(config->aml_ej0_name[0])))
> +    {
> +         rmvc_pcrm = inl(PCI_RMV_BASE);
> +	  printf("rmvc_pcrm is %x\n", rmvc_pcrm);
> +        for(i = 0;  i < config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]); i ++)
> +        {
> +            /* Slot is in byte 2 in _ADR */
> +            unsigned char slot = dsdt[config->aml_adr_dword[i] + 2] & 0x1F;
> +            /* Sanity check */
> +            if (memcmp(dsdt + config->aml_ej0_name[i], "_EJ0", 4)) {
> +                goto oom;
> +            }
> +            if (!(rmvc_pcrm & (0x1 << slot))) {
> +                memcpy(dsdt + config->aml_ej0_name[i], "EJ0_", 4);
> +            }
> +        }
>       }
>   
> +    nr_processor_objects = HVM_MAX_VCPUS;
>       /*
>        * N.B. ACPI 1.0 operating systems may not handle FADT with revision 2
>        * or above properly, notably Windows 2000, which tries to copy FADT
> diff -urN hvmloader/acpi/dsdt.asl hvmloader_new//acpi/dsdt.asl
> --- hvmloader/acpi/dsdt.asl	2013-10-16 11:56:20.000000000 +0800
> +++ hvmloader_new//acpi/dsdt.asl	2013-10-16 11:46:52.000000000 +0800
> @@ -16,6 +16,7 @@
>    * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
>    * Place - Suite 330, Boston, MA 02111-1307 USA.
>    */
> +ACPI_EXTRACT_ALL_CODE AmlCode
>   
>   DefinitionBlock ("DSDT.aml", "DSDT", 2, "Xen", "HVM", 0)
>   {
> diff -urN hvmloader/acpi/mk_dsdt.c hvmloader_new//acpi/mk_dsdt.c
> --- hvmloader/acpi/mk_dsdt.c	2013-10-16 11:56:32.000000000 +0800
> +++ hvmloader_new//acpi/mk_dsdt.c	2013-10-16 11:46:52.000000000 +0800
> @@ -368,7 +368,9 @@
>           /* hotplug_slot */
>           for (slot = 1; slot <= 31; slot++) {
>               push_block("Device", "S%i", slot); {
> +                printf("ACPI_EXTRACT_NAME_DWORD_CONST aml_adr_dword\n");
>                   stmt("Name", "_ADR, %#06x0000", slot);
> +                printf("ACPI_EXTRACT_METHOD_STRING aml_ej0_name\n");
>                   push_block("Method", "_EJ0,1"); {
>                       stmt("Store", "ShiftLeft(1, %#06x), B0EJ", slot);
>                       stmt("Return", "0x0");
> @@ -453,7 +455,7 @@
>   /*
>    * Local variables:
>    * mode: C
> - * c-file-style: "BSD"
> + * c-set-style: "BSD"
>    * c-basic-offset: 4
>    * tab-width: 4
>    * indent-tabs-mode: nil
> diff -urN hvmloader/ovmf.c hvmloader_new//ovmf.c
> --- hvmloader/ovmf.c	2013-10-16 11:57:15.000000000 +0800
> +++ hvmloader_new//ovmf.c	2013-10-16 11:57:48.000000000 +0800
> @@ -79,7 +79,11 @@
>           .dsdt_anycpu = dsdt_anycpu,
>           .dsdt_anycpu_len = dsdt_anycpu_len,
>           .dsdt_15cpu = NULL,
> -        .dsdt_15cpu_len = 0
> +        .dsdt_15cpu_len = 0,
> +        .aml_ej0_name = NULL,
> +        .aml_adr_dword = NULL,
> +        .aml_ej0_name_len = 0,
> +        .aml_adr_dword_len = 0,
>       };
>   
>       acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
> diff -urN hvmloader/rombios.c hvmloader_new//rombios.c
> --- hvmloader/rombios.c	2013-10-16 11:57:15.000000000 +0800
> +++ hvmloader_new//rombios.c	2013-10-16 11:57:48.000000000 +0800
> @@ -179,6 +179,10 @@
>           .dsdt_anycpu_len = dsdt_anycpu_len,
>           .dsdt_15cpu = dsdt_15cpu,
>           .dsdt_15cpu_len = dsdt_15cpu_len,
> +        .aml_ej0_name = NULL,
> +        .aml_adr_dword = NULL,
> +        .aml_ej0_name_len = 0,
> +        .aml_adr_dword_len = 0,
>       };
>   
>       acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
> diff -urN hvmloader/seabios.c hvmloader_new//seabios.c
> --- hvmloader/seabios.c	2013-10-16 11:57:15.000000000 +0800
> +++ hvmloader_new//seabios.c	2013-10-16 11:57:48.000000000 +0800
> @@ -33,6 +33,10 @@
>   
>   extern unsigned char dsdt_anycpu_qemu_xen[];
>   extern int dsdt_anycpu_qemu_xen_len;
> +extern unsigned short dsdt_anycpu_qemu_xen_aml_ej0_name[];
> +extern unsigned short dsdt_anycpu_qemu_xen_aml_adr_dword[];
> +extern int dsdt_anycpu_qemu_xen_aml_ej0_name_len;
> +extern int dsdt_anycpu_qemu_xen_aml_adr_dword_len;
>   
>   struct seabios_info {
>       char signature[14]; /* XenHVMSeaBIOS\0 */
> @@ -99,6 +103,10 @@
>           .dsdt_anycpu_len = dsdt_anycpu_qemu_xen_len,
>           .dsdt_15cpu = NULL,
>           .dsdt_15cpu_len = 0,
> +        .aml_ej0_name = dsdt_anycpu_qemu_xen_aml_ej0_name,
> +        .aml_adr_dword = dsdt_anycpu_qemu_xen_aml_adr_dword,
> +        .aml_ej0_name_len = dsdt_anycpu_qemu_xen_aml_ej0_name_len,
> +        .aml_adr_dword_len = dsdt_anycpu_qemu_xen_aml_adr_dword_len,
>       };
>   
>       acpi_build_tables(&config, rsdp);
> diff -urN hvmloader/tools/acpi_extract.py hvmloader_new//tools/acpi_extract.py
> --- hvmloader/tools/acpi_extract.py	1970-01-01 08:00:00.000000000 +0800
> +++ hvmloader_new//tools/acpi_extract.py	2013-10-16 11:46:52.000000000 +0800
> @@ -0,0 +1,308 @@
> +#!/usr/bin/python
> +# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin<mst@redhat.com>
> +#
> +# This file may be distributed under the terms of the GNU GPLv3 license.
> +
> +# Process mixed ASL/AML listing (.lst file) produced by iasl -l
> +# Locate and execute ACPI_EXTRACT directives, output offset info
> +#
> +# Documentation of ACPI_EXTRACT_* directive tags:
> +#
> +# These directive tags output offset information from AML for BIOS runtime
> +# table generation.
> +# Each directive is of the form:
> +# ACPI_EXTRACT_<TYPE> <array_name> <Operator> (...)
> +# and causes the extractor to create an array
> +# named <array_name> with offset, in the generated AML,
> +# of an object of a given type in the following <Operator>.
> +#
> +# A directive must fit on a single code line.
> +#
> +# Object type in AML is verified, a mismatch causes a build failure.
> +#
> +# Directives and operators currently supported are:
> +# ACPI_EXTRACT_NAME_DWORD_CONST - extract a Dword Const object from Name()
> +# ACPI_EXTRACT_NAME_WORD_CONST - extract a Word Const object from Name()
> +# ACPI_EXTRACT_NAME_BYTE_CONST - extract a Byte Const object from Name()
> +# ACPI_EXTRACT_METHOD_STRING - extract a NameString from Method()
> +# ACPI_EXTRACT_NAME_STRING - extract a NameString from Name()
> +# ACPI_EXTRACT_PROCESSOR_START - start of Processor() block
> +# ACPI_EXTRACT_PROCESSOR_STRING - extract a NameString from Processor()
> +# ACPI_EXTRACT_PROCESSOR_END - offset at last byte of Processor() + 1
> +# ACPI_EXTRACT_PKG_START - start of Package block
> +#
> +# ACPI_EXTRACT_ALL_CODE - create an array storing the generated AML bytecode
> +#
> +# ACPI_EXTRACT is not allowed anywhere else in code, except in comments.
> +
> +import re;
> +import sys;
> +import fileinput;
> +
> +aml = []
> +asl = []
> +output = {}
> +debug = ""
> +
> +class asl_line:
> +    line = None
> +    lineno = None
> +    aml_offset = None
> +
> +def die(diag):
> +    sys.stderr.write("Error: %s; %s\n" % (diag, debug))
> +    sys.exit(1)
> +
> +#Store an ASL command, matching AML offset, and input line (for debugging)
> +def add_asl(lineno, line):
> +    l = asl_line()
> +    l.line = line
> +    l.lineno = lineno
> +    l.aml_offset = len(aml)
> +    asl.append(l)
> +
> +#Store an AML byte sequence
> +#Verify that offset output by iasl matches # of bytes so far
> +def add_aml(offset, line):
> +    o = int(offset, 16);
> +    # Sanity check: offset must match size of code so far
> +    if (o != len(aml)):
> +        die("Offset 0x%x != 0x%x" % (o, len(aml)))
> +    # Strip any trailing dots and ASCII dump after "
> +    line = re.sub(r'\s*\.*\s*".*$',"", line)
> +    # Strip traling whitespace
> +    line = re.sub(r'\s+$',"", line)
> +    # Strip leading whitespace
> +    line = re.sub(r'^\s+',"", line)
> +    # Split on whitespace
> +    code = re.split(r'\s+', line)
> +    for c in code:
> +        # Require a legal hex number, two digits
> +        if (not(re.search(r'^[0-9A-Fa-f][0-9A-Fa-f]$', c))):
> +            die("Unexpected octet %s" % c);
> +        aml.append(int(c, 16));
> +
> +# Process aml bytecode array, decoding AML
> +def aml_pkglen_bytes(offset):
> +    # PkgLength can be multibyte. Bits 8-7 give the # of extra bytes.
> +    pkglenbytes = aml[offset] >> 6;
> +    return pkglenbytes + 1
> +
> +def aml_pkglen(offset):
> +    pkgstart = offset
> +    pkglenbytes = aml_pkglen_bytes(offset)
> +    pkglen = aml[offset] & 0x3F
> +    # If multibyte, first nibble only uses bits 0-3
> +    if ((pkglenbytes > 0) and (pkglen & 0x30)):
> +        die("PkgLen bytes 0x%x but first nibble 0x%x expected 0x0X" %
> +            (pkglen, pkglen))
> +    offset += 1
> +    pkglenbytes -= 1
> +    for i in range(pkglenbytes):
> +        pkglen |= aml[offset + i] << (i * 8 + 4)
> +    if (len(aml) < pkgstart + pkglen):
> +        die("PckgLen 0x%x at offset 0x%x exceeds AML size 0x%x" %
> +            (pkglen, offset, len(aml)))
> +    return pkglen
> +
> +# Given method offset, find its NameString offset
> +def aml_method_string(offset):
> +    #0x14 MethodOp PkgLength NameString MethodFlags TermList
> +    if (aml[offset] != 0x14):
> +        die( "Method offset 0x%x: expected 0x14 actual 0x%x" %
> +             (offset, aml[offset]));
> +    offset += 1;
> +    pkglenbytes = aml_pkglen_bytes(offset)
> +    offset += pkglenbytes;
> +    return offset;
> +
> +# Given name offset, find its NameString offset
> +def aml_name_string(offset):
> +    #0x08 NameOp NameString DataRef
> +    if (aml[offset] != 0x08):
> +        die( "Name offset 0x%x: expected 0x08 actual 0x%x" %
> +             (offset, aml[offset]));
> +    offset += 1
> +    # Block Name Modifier. Skip it.
> +    if (aml[offset] == 0x5c or aml[offset] == 0x5e):
> +        offset += 1
> +    return offset;
> +
> +# Given data offset, find dword const offset
> +def aml_data_dword_const(offset):
> +    #0x08 NameOp NameString DataRef
> +    if (aml[offset] != 0x0C):
> +        die( "Name offset 0x%x: expected 0x0C actual 0x%x" %
> +             (offset, aml[offset]));
> +    return offset + 1;
> +
> +# Given data offset, find word const offset
> +def aml_data_word_const(offset):
> +    #0x08 NameOp NameString DataRef
> +    if (aml[offset] != 0x0B):
> +        die( "Name offset 0x%x: expected 0x0B actual 0x%x" %
> +             (offset, aml[offset]));
> +    return offset + 1;
> +
> +# Given data offset, find byte const offset
> +def aml_data_byte_const(offset):
> +    #0x08 NameOp NameString DataRef
> +    if (aml[offset] != 0x0A):
> +        die( "Name offset 0x%x: expected 0x0A actual 0x%x" %
> +             (offset, aml[offset]));
> +    return offset + 1;
> +
> +# Given name offset, find dword const offset
> +def aml_name_dword_const(offset):
> +    return aml_data_dword_const(aml_name_string(offset) + 4)
> +
> +# Given name offset, find word const offset
> +def aml_name_word_const(offset):
> +    return aml_data_word_const(aml_name_string(offset) + 4)
> +
> +# Given name offset, find byte const offset
> +def aml_name_byte_const(offset):
> +    return aml_data_byte_const(aml_name_string(offset) + 4)
> +
> +def aml_processor_start(offset):
> +    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
> +    if ((aml[offset] != 0x5B) or (aml[offset + 1] != 0x83)):
> +        die( "Name offset 0x%x: expected 0x5B 0x83 actual 0x%x 0x%x" %
> +             (offset, aml[offset], aml[offset + 1]));
> +    return offset
> +
> +def aml_processor_string(offset):
> +    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
> +    start = aml_processor_start(offset)
> +    offset += 2
> +    pkglenbytes = aml_pkglen_bytes(offset)
> +    offset += pkglenbytes
> +    return offset
> +
> +def aml_processor_end(offset):
> +    start = aml_processor_start(offset)
> +    offset += 2
> +    pkglenbytes = aml_pkglen_bytes(offset)
> +    pkglen = aml_pkglen(offset)
> +    return offset + pkglen
> +
> +def aml_package_start(offset):
> +    offset = aml_name_string(offset) + 4
> +    # 0x12 PkgLength NumElements PackageElementList
> +    if (aml[offset] != 0x12):
> +        die( "Name offset 0x%x: expected 0x12 actual 0x%x" %
> +             (offset, aml[offset]));
> +    offset += 1
> +    return offset + aml_pkglen_bytes(offset) + 1
> +
> +lineno = 0
> +for line in fileinput.input():
> +    # Strip trailing newline
> +    line = line.rstrip();
> +    # line number and debug string to output in case of errors
> +    lineno = lineno + 1
> +    debug = "input line %d: %s" % (lineno, line)
> +    #ASL listing: space, then line#, then ...., then code
> +    pasl = re.compile('^\s+([0-9]+)\.\.\.\.\s*')
> +    m = pasl.search(line)
> +    if (m):
> +        add_asl(lineno, pasl.sub("", line));
> +    # AML listing: offset in hex, then ...., then code
> +    paml = re.compile('^([0-9A-Fa-f]+)\.\.\.\.\s*')
> +    m = paml.search(line)
> +    if (m):
> +        add_aml(m.group(1), paml.sub("", line))
> +
> +# Now go over code
> +# Track AML offset of a previous non-empty ASL command
> +prev_aml_offset = -1
> +for i in range(len(asl)):
> +    debug = "input line %d: %s" % (asl[i].lineno, asl[i].line)
> +
> +    l = asl[i].line
> +
> +    # skip if not an extract directive
> +    a = len(re.findall(r'ACPI_EXTRACT', l))
> +    if (not a):
> +        # If not empty, store AML offset. Will be used for sanity checks
> +        # IASL seems to put {}. at random places in the listing.
> +        # Ignore any non-words for the purpose of this test.
> +        m = re.search(r'\w+', l)
> +        if (m):
> +                prev_aml_offset = asl[i].aml_offset
> +        continue
> +
> +    if (a > 1):
> +        die("Expected at most one ACPI_EXTRACT per line, actual %d" % a)
> +
> +    mext = re.search(r'''
> +                      ^\s* # leading whitespace
> +                      /\*\s* # start C comment
> +                      (ACPI_EXTRACT_\w+) # directive: group(1)
> +                      \s+ # whitspace separates directive from array name
> +                      (\w+) # array name: group(2)
> +                      \s*\*/ # end of C comment
> +                      \s*$ # trailing whitespace
> +                      ''', l, re.VERBOSE)
> +    if (not mext):
> +        die("Stray ACPI_EXTRACT in input")
> +
> +    # previous command must have produced some AML,
> +    # otherwise we are in a middle of a block
> +    if (prev_aml_offset == asl[i].aml_offset):
> +        die("ACPI_EXTRACT directive in the middle of a block")
> +
> +    directive = mext.group(1)
> +    array = mext.group(2)
> +    offset = asl[i].aml_offset
> +
> +    if (directive == "ACPI_EXTRACT_ALL_CODE"):
> +        if array in output:
> +            die("%s directive used more than once" % directive)
> +        output[array] = aml
> +        continue
> +    if (directive == "ACPI_EXTRACT_NAME_DWORD_CONST"):
> +        offset = aml_name_dword_const(offset)
> +    elif (directive == "ACPI_EXTRACT_NAME_WORD_CONST"):
> +        offset = aml_name_word_const(offset)
> +    elif (directive == "ACPI_EXTRACT_NAME_BYTE_CONST"):
> +        offset = aml_name_byte_const(offset)
> +    elif (directive == "ACPI_EXTRACT_NAME_STRING"):
> +        offset = aml_name_string(offset)
> +    elif (directive == "ACPI_EXTRACT_METHOD_STRING"):
> +        offset = aml_method_string(offset)
> +    elif (directive == "ACPI_EXTRACT_PROCESSOR_START"):
> +        offset = aml_processor_start(offset)
> +    elif (directive == "ACPI_EXTRACT_PROCESSOR_STRING"):
> +        offset = aml_processor_string(offset)
> +    elif (directive == "ACPI_EXTRACT_PROCESSOR_END"):
> +        offset = aml_processor_end(offset)
> +    elif (directive == "ACPI_EXTRACT_PKG_START"):
> +        offset = aml_package_start(offset)
> +    else:
> +        die("Unsupported directive %s" % directive)
> +
> +    if array not in output:
> +        output[array] = []
> +    output[array].append(offset)
> +
> +debug = "at end of file"
> +
> +def get_value_type(maxvalue):
> +    #Use type large enough to fit the table
> +    if (maxvalue >= 0x10000):
> +            return "int"
> +    elif (maxvalue >= 0x100):
> +            return "short"
> +    else:
> +            return "char"
> +
> +# Pretty print output
> +for array in output.keys():
> +    otype = get_value_type(max(output[array]))
> +    odata = []
> +    for value in output[array]:
> +        odata.append("0x%x" % value)
> +    sys.stdout.write("unsigned %s %s[] = {\n" % (otype, array))
> +    sys.stdout.write(",\n".join(odata))
> +    sys.stdout.write('\n};\n');
> diff -urN hvmloader/tools/acpi_extract_preprocess.py hvmloader_new//tools/acpi_extract_preprocess.py
> --- hvmloader/tools/acpi_extract_preprocess.py	1970-01-01 08:00:00.000000000 +0800
> +++ hvmloader_new//tools/acpi_extract_preprocess.py	2013-10-16 11:46:53.000000000 +0800
> @@ -0,0 +1,41 @@
> +#!/usr/bin/python
> +# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin<mst@redhat.com>
> +#
> +# This file may be distributed under the terms of the GNU GPLv3 license.
> +
> +# Read a preprocessed ASL listing and put each ACPI_EXTRACT
> +# directive in a comment, to make iasl skip it.
> +# We also put each directive on a new line, the machinery
> +# in tools/acpi_extract.py requires this.
> +
> +import re;
> +import sys;
> +import fileinput;
> +
> +def die(diag):
> +    sys.stderr.write("Error: %s\n" % (diag))
> +    sys.exit(1)
> +
> +# Note: () around pattern make split return matched string as part of list
> +psplit = re.compile(r''' (
> +                          \b # At word boundary
> +                          ACPI_EXTRACT_\w+ # directive
> +                          \s+ # some whitespace
> +                          \w+ # array name
> +                         )''', re.VERBOSE);
> +
> +lineno = 0
> +for line in fileinput.input():
> +    # line number and debug string to output in case of errors
> +    lineno = lineno + 1
> +    debug = "input line %d: %s" % (lineno, line.rstrip())
> +
> +    s = psplit.split(line);
> +    # The way split works, each odd item is the matching ACPI_EXTRACT directive.
> +    # Put each in a comment, and on a line by itself.
> +    for i in range(len(s)):
> +        if (i % 2):
> +            sys.stdout.write("\n/* %s */\n" % s[i])
> +        else:
> +            sys.stdout.write(s[i])
> +


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [Xen-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
  2013-10-16  6:30 [Qemu-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching Gonglei (Arei)
                   ` (2 preceding siblings ...)
  2013-10-16  9:19 ` Ian Campbell
@ 2013-10-16  9:19 ` Ian Campbell
  2013-10-16  9:54 ` Jan Beulich
  2013-10-16  9:54 ` Jan Beulich
  5 siblings, 0 replies; 38+ messages in thread
From: Ian Campbell @ 2013-10-16  9:19 UTC (permalink / raw)
  To: Gonglei (Arei)
  Cc: Hanweidong (Randy),
	Stefano Stabellini, Yanqiangjun, Luonengjun, qemu-devel,
	xen-devel, Fabio Fantoni, anthony.perard, Gaowei (UVP),
	Huangweidong (Hardware)

On Wed, 2013-10-16 at 06:30 +0000, Gonglei (Arei) wrote:
> http://lists.xen.org/archives/html/xen-devel/2013-09/msg03113.html
> As said above, In Xen platform, after using upstream qemu, all pci devices can be unpluged in the windows guest.
> In this situation, the windows guest may occur blue screen when VM' user click the icon of pass-through Graphics card for trying to unplug the device.
> 
> The kvm system doesn't have this problem for the use of seabios.
> http://www.seabios.org/pipermail/seabios/2011-September/002293.html
> The patch above in seabios solves the problem. The patch is ported in hvmloader and works well.
> 
> This is done by runtime patching:
> - Rename _EJ0 methods for PCI slots in DSDT to EJ0_:
>   note that this has the same checksum, but
>   is ignored by OSPM.
> - At compile time, look for these methods in ASL source,
>   find the matching AML, and store the offsets of these methods
>   in a table named aml_ej0_data.
> - At run time, go over aml_ej0_data, check which slots 
>   not support hotplug and patch the ACPI table, replacing _EJ0 with EJ0_.

This needs a Signed-off-by, see
http://wiki.xen.org/wiki/Submitting_Xen_Patches for what this means you
are agreeing to.

> The files *.py are from seabios

Which is GPLv3 only AFAIK and therefore we need to think carefully about
whether this is acceptable in the Xen code base.

I think it is OK for a compile time only component. What do others
think?

> diff -urN hvmloader/acpi/Makefile hvmloader_new//acpi/Makefile
> --- hvmloader/acpi/Makefile	2013-10-16 11:51:53.000000000 +0800
> +++ hvmloader_new//acpi/Makefile	2013-10-16 11:51:58.000000000 +0800
> @@ -36,18 +36,34 @@
>  
>  dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
>  	awk 'NR > 1 {print s} {s=$$0}' $< > $@
> -	./mk_dsdt --dm-version qemu-xen >> $@
> +	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@
> +	./mk_dsdt --dm-version qemu-xen >> $@	
> +	sed -i 's/aml_ej0_name/dsdt_anycpu_qemu_xen_aml_ej0_name/g' $@
> +	sed -i 's/aml_adr_dword/dsdt_anycpu_qemu_xen_aml_adr_dword/g' $@
>  
>  # NB. awk invocation is a portable alternative to 'head -n -1'
>  dsdt_%cpu.asl: dsdt.asl mk_dsdt
>  	awk 'NR > 1 {print s} {s=$$0}' $< > $@
> +	sed -i 's/AmlCode/dsdt_$*cpu/g' $@
>  	./mk_dsdt --maxcpu $*  >> $@
>  
>  $(filter dsdt_%.c,$(C_SRC)): %.c: iasl %.asl
> -	iasl -vs -p $* -tc $*.asl
> -	sed -e 's/AmlCode/$*/g' $*.hex >$@
> +	cpp -P $*.asl > $*.asl.i.orig
> +	/usr/bin/python ../tools/acpi_extract_preprocess.py $*.asl.i.orig > $*.asl.i
> +	iasl -vs -l -tc -p $* $*.asl.i
> +	/usr/bin/python ../tools/acpi_extract.py $*.lst > $@
>  	echo "int $*_len=sizeof($*);" >>$@
> -	rm -f $*.aml $*.hex
> +	rm -f $*.aml $*.hex $*.asl.i.orig $*.asl.i $*.lst
> +
> +dsdt_anycpu_qemu_xen.c:iasl dsdt_anycpu_qemu_xen.asl
> +	cpp -P $*.asl > $*.asl.i.orig
> +	/usr/bin/python ../tools/acpi_extract_preprocess.py $*.asl.i.orig > $*.asl.i
> +	iasl -vs -l -tc -p $* $*.asl.i
> +	/usr/bin/python ../tools/acpi_extract.py $*.lst > $@
> +	echo "int $*_len=sizeof($*);" >>$@
> +	echo "int $*_aml_ej0_name_len=sizeof($*_aml_ej0_name);" >>$@
> +	echo "int $*_aml_adr_dword_len=sizeof($*_aml_adr_dword);" >>$@
> +	rm -f $*.aml $*.hex $*.asl.i.orig $*.asl.i $*.lst
>  
>  iasl:
>  	@echo
> @@ -64,7 +80,7 @@
>  
>  clean:
>  	rm -rf *.a *.o $(IASL_VER) $(IASL_VER).tar.gz $(DEPS)
> -	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl
> +	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl *.asl.i *.asl.i.orig *.lst
>  
>  install: all
>  
> diff -urN hvmloader/acpi/acpi2_0.h hvmloader_new//acpi/acpi2_0.h
> --- hvmloader/acpi/acpi2_0.h	2013-10-16 11:54:49.000000000 +0800
> +++ hvmloader_new//acpi/acpi2_0.h	2013-10-16 11:46:52.000000000 +0800
> @@ -396,6 +396,11 @@
>      int dsdt_anycpu_len;
>      unsigned char *dsdt_15cpu;
>      int dsdt_15cpu_len;
> +    unsigned short *aml_ej0_name;
> +    unsigned short *aml_adr_dword;
> +    int aml_ej0_name_len;
> +    int aml_adr_dword_len;
> +    
>  };
>  
>  void acpi_build_tables(struct acpi_config *config, unsigned int physical);
> diff -urN hvmloader/acpi/build.c hvmloader_new//acpi/build.c
> --- hvmloader/acpi/build.c	2013-10-16 11:55:55.000000000 +0800
> +++ hvmloader_new//acpi/build.c	2013-10-16 11:46:52.000000000 +0800
> @@ -30,6 +30,9 @@
>  #define align16(sz)        (((sz) + 15) & ~15)
>  #define fixed_strcpy(d, s) strncpy((d), (s), sizeof(d))
>  
> +
> +#define PCI_RMV_BASE 0xae0c
> +
>  extern struct acpi_20_rsdp Rsdp;
>  extern struct acpi_20_rsdt Rsdt;
>  extern struct acpi_20_xsdt Xsdt;
> @@ -404,6 +407,7 @@
>      unsigned char       *dsdt;
>      unsigned long        secondary_tables[ACPI_MAX_SECONDARY_TABLES];
>      int                  nr_secondaries, i;
> +    unsigned int rmvc_pcrm = 0;
>  
>      /* Allocate and initialise the acpi info area. */
>      mem_hole_populate_ram(ACPI_INFO_PHYSICAL_ADDRESS >> PAGE_SHIFT, 1);
> @@ -438,9 +442,26 @@
>          dsdt = mem_alloc(config->dsdt_anycpu_len, 16);
>          if (!dsdt) goto oom;
>          memcpy(dsdt, config->dsdt_anycpu, config->dsdt_anycpu_len);
> -        nr_processor_objects = HVM_MAX_VCPUS;
> +    if(config->aml_adr_dword_len && config->aml_ej0_name_len &&
> +        (config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]) == config->aml_ej0_name_len/sizeof(config->aml_ej0_name[0])))
> +    {
> +         rmvc_pcrm = inl(PCI_RMV_BASE); 
> +	  printf("rmvc_pcrm is %x\n", rmvc_pcrm);
> +        for(i = 0;  i < config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]); i ++)
> +        {
> +            /* Slot is in byte 2 in _ADR */
> +            unsigned char slot = dsdt[config->aml_adr_dword[i] + 2] & 0x1F;
> +            /* Sanity check */
> +            if (memcmp(dsdt + config->aml_ej0_name[i], "_EJ0", 4)) {
> +                goto oom;
> +            }
> +            if (!(rmvc_pcrm & (0x1 << slot))) {
> +                memcpy(dsdt + config->aml_ej0_name[i], "EJ0_", 4);
> +            }
> +        }
>      }
>  
> +    nr_processor_objects = HVM_MAX_VCPUS;
>      /*
>       * N.B. ACPI 1.0 operating systems may not handle FADT with revision 2
>       * or above properly, notably Windows 2000, which tries to copy FADT
> diff -urN hvmloader/acpi/dsdt.asl hvmloader_new//acpi/dsdt.asl
> --- hvmloader/acpi/dsdt.asl	2013-10-16 11:56:20.000000000 +0800
> +++ hvmloader_new//acpi/dsdt.asl	2013-10-16 11:46:52.000000000 +0800
> @@ -16,6 +16,7 @@
>   * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
>   * Place - Suite 330, Boston, MA 02111-1307 USA.
>   */
> +ACPI_EXTRACT_ALL_CODE AmlCode
>  
>  DefinitionBlock ("DSDT.aml", "DSDT", 2, "Xen", "HVM", 0)
>  {
> diff -urN hvmloader/acpi/mk_dsdt.c hvmloader_new//acpi/mk_dsdt.c
> --- hvmloader/acpi/mk_dsdt.c	2013-10-16 11:56:32.000000000 +0800
> +++ hvmloader_new//acpi/mk_dsdt.c	2013-10-16 11:46:52.000000000 +0800
> @@ -368,7 +368,9 @@
>          /* hotplug_slot */
>          for (slot = 1; slot <= 31; slot++) {
>              push_block("Device", "S%i", slot); {
> +                printf("ACPI_EXTRACT_NAME_DWORD_CONST aml_adr_dword\n");
>                  stmt("Name", "_ADR, %#06x0000", slot);
> +                printf("ACPI_EXTRACT_METHOD_STRING aml_ej0_name\n");
>                  push_block("Method", "_EJ0,1"); {
>                      stmt("Store", "ShiftLeft(1, %#06x), B0EJ", slot);
>                      stmt("Return", "0x0");
> @@ -453,7 +455,7 @@
>  /*
>   * Local variables:
>   * mode: C
> - * c-file-style: "BSD"
> + * c-set-style: "BSD"
>   * c-basic-offset: 4
>   * tab-width: 4
>   * indent-tabs-mode: nil
> diff -urN hvmloader/ovmf.c hvmloader_new//ovmf.c
> --- hvmloader/ovmf.c	2013-10-16 11:57:15.000000000 +0800
> +++ hvmloader_new//ovmf.c	2013-10-16 11:57:48.000000000 +0800
> @@ -79,7 +79,11 @@
>          .dsdt_anycpu = dsdt_anycpu,
>          .dsdt_anycpu_len = dsdt_anycpu_len,
>          .dsdt_15cpu = NULL, 
> -        .dsdt_15cpu_len = 0
> +        .dsdt_15cpu_len = 0,
> +        .aml_ej0_name = NULL,
> +        .aml_adr_dword = NULL,
> +        .aml_ej0_name_len = 0,
> +        .aml_adr_dword_len = 0,
>      };
>  
>      acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
> diff -urN hvmloader/rombios.c hvmloader_new//rombios.c
> --- hvmloader/rombios.c	2013-10-16 11:57:15.000000000 +0800
> +++ hvmloader_new//rombios.c	2013-10-16 11:57:48.000000000 +0800
> @@ -179,6 +179,10 @@
>          .dsdt_anycpu_len = dsdt_anycpu_len,
>          .dsdt_15cpu = dsdt_15cpu,
>          .dsdt_15cpu_len = dsdt_15cpu_len,
> +        .aml_ej0_name = NULL,
> +        .aml_adr_dword = NULL,
> +        .aml_ej0_name_len = 0,
> +        .aml_adr_dword_len = 0,
>      };
>  
>      acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
> diff -urN hvmloader/seabios.c hvmloader_new//seabios.c
> --- hvmloader/seabios.c	2013-10-16 11:57:15.000000000 +0800
> +++ hvmloader_new//seabios.c	2013-10-16 11:57:48.000000000 +0800
> @@ -33,6 +33,10 @@
>  
>  extern unsigned char dsdt_anycpu_qemu_xen[];
>  extern int dsdt_anycpu_qemu_xen_len;
> +extern unsigned short dsdt_anycpu_qemu_xen_aml_ej0_name[];
> +extern unsigned short dsdt_anycpu_qemu_xen_aml_adr_dword[];
> +extern int dsdt_anycpu_qemu_xen_aml_ej0_name_len;
> +extern int dsdt_anycpu_qemu_xen_aml_adr_dword_len;
>  
>  struct seabios_info {
>      char signature[14]; /* XenHVMSeaBIOS\0 */
> @@ -99,6 +103,10 @@
>          .dsdt_anycpu_len = dsdt_anycpu_qemu_xen_len,
>          .dsdt_15cpu = NULL,
>          .dsdt_15cpu_len = 0,
> +        .aml_ej0_name = dsdt_anycpu_qemu_xen_aml_ej0_name,
> +        .aml_adr_dword = dsdt_anycpu_qemu_xen_aml_adr_dword,
> +        .aml_ej0_name_len = dsdt_anycpu_qemu_xen_aml_ej0_name_len,
> +        .aml_adr_dword_len = dsdt_anycpu_qemu_xen_aml_adr_dword_len,
>      };
>  
>      acpi_build_tables(&config, rsdp);
> diff -urN hvmloader/tools/acpi_extract.py hvmloader_new//tools/acpi_extract.py
> --- hvmloader/tools/acpi_extract.py	1970-01-01 08:00:00.000000000 +0800
> +++ hvmloader_new//tools/acpi_extract.py	2013-10-16 11:46:52.000000000 +0800
> @@ -0,0 +1,308 @@
> +#!/usr/bin/python
> +# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
> +#
> +# This file may be distributed under the terms of the GNU GPLv3 license.
> +
> +# Process mixed ASL/AML listing (.lst file) produced by iasl -l
> +# Locate and execute ACPI_EXTRACT directives, output offset info
> +# 
> +# Documentation of ACPI_EXTRACT_* directive tags:
> +# 
> +# These directive tags output offset information from AML for BIOS runtime
> +# table generation.
> +# Each directive is of the form:
> +# ACPI_EXTRACT_<TYPE> <array_name> <Operator> (...)
> +# and causes the extractor to create an array
> +# named <array_name> with offset, in the generated AML,
> +# of an object of a given type in the following <Operator>.
> +# 
> +# A directive must fit on a single code line.
> +# 
> +# Object type in AML is verified, a mismatch causes a build failure.
> +# 
> +# Directives and operators currently supported are:
> +# ACPI_EXTRACT_NAME_DWORD_CONST - extract a Dword Const object from Name()
> +# ACPI_EXTRACT_NAME_WORD_CONST - extract a Word Const object from Name()
> +# ACPI_EXTRACT_NAME_BYTE_CONST - extract a Byte Const object from Name()
> +# ACPI_EXTRACT_METHOD_STRING - extract a NameString from Method()
> +# ACPI_EXTRACT_NAME_STRING - extract a NameString from Name()
> +# ACPI_EXTRACT_PROCESSOR_START - start of Processor() block
> +# ACPI_EXTRACT_PROCESSOR_STRING - extract a NameString from Processor()
> +# ACPI_EXTRACT_PROCESSOR_END - offset at last byte of Processor() + 1
> +# ACPI_EXTRACT_PKG_START - start of Package block
> +#
> +# ACPI_EXTRACT_ALL_CODE - create an array storing the generated AML bytecode
> +# 
> +# ACPI_EXTRACT is not allowed anywhere else in code, except in comments.
> +
> +import re;
> +import sys;
> +import fileinput;
> +
> +aml = []
> +asl = []
> +output = {}
> +debug = ""
> +
> +class asl_line:
> +    line = None
> +    lineno = None
> +    aml_offset = None
> +
> +def die(diag):
> +    sys.stderr.write("Error: %s; %s\n" % (diag, debug))
> +    sys.exit(1)
> +    
> +#Store an ASL command, matching AML offset, and input line (for debugging)
> +def add_asl(lineno, line):
> +    l = asl_line()
> +    l.line = line
> +    l.lineno = lineno
> +    l.aml_offset = len(aml)
> +    asl.append(l)
> +
> +#Store an AML byte sequence
> +#Verify that offset output by iasl matches # of bytes so far
> +def add_aml(offset, line):
> +    o = int(offset, 16);
> +    # Sanity check: offset must match size of code so far
> +    if (o != len(aml)):
> +        die("Offset 0x%x != 0x%x" % (o, len(aml)))
> +    # Strip any trailing dots and ASCII dump after "
> +    line = re.sub(r'\s*\.*\s*".*$',"", line)
> +    # Strip traling whitespace
> +    line = re.sub(r'\s+$',"", line)
> +    # Strip leading whitespace
> +    line = re.sub(r'^\s+',"", line)
> +    # Split on whitespace
> +    code = re.split(r'\s+', line)
> +    for c in code:
> +        # Require a legal hex number, two digits
> +        if (not(re.search(r'^[0-9A-Fa-f][0-9A-Fa-f]$', c))):
> +            die("Unexpected octet %s" % c);
> +        aml.append(int(c, 16));
> +
> +# Process aml bytecode array, decoding AML
> +def aml_pkglen_bytes(offset):
> +    # PkgLength can be multibyte. Bits 8-7 give the # of extra bytes.
> +    pkglenbytes = aml[offset] >> 6;
> +    return pkglenbytes + 1
> +
> +def aml_pkglen(offset):
> +    pkgstart = offset
> +    pkglenbytes = aml_pkglen_bytes(offset)
> +    pkglen = aml[offset] & 0x3F
> +    # If multibyte, first nibble only uses bits 0-3
> +    if ((pkglenbytes > 0) and (pkglen & 0x30)):
> +        die("PkgLen bytes 0x%x but first nibble 0x%x expected 0x0X" %
> +            (pkglen, pkglen))
> +    offset += 1
> +    pkglenbytes -= 1
> +    for i in range(pkglenbytes):
> +        pkglen |= aml[offset + i] << (i * 8 + 4)
> +    if (len(aml) < pkgstart + pkglen):
> +        die("PckgLen 0x%x at offset 0x%x exceeds AML size 0x%x" %
> +            (pkglen, offset, len(aml)))
> +    return pkglen
> +
> +# Given method offset, find its NameString offset
> +def aml_method_string(offset):
> +    #0x14 MethodOp PkgLength NameString MethodFlags TermList
> +    if (aml[offset] != 0x14):
> +        die( "Method offset 0x%x: expected 0x14 actual 0x%x" %
> +             (offset, aml[offset]));
> +    offset += 1;
> +    pkglenbytes = aml_pkglen_bytes(offset)
> +    offset += pkglenbytes;
> +    return offset;
> +
> +# Given name offset, find its NameString offset
> +def aml_name_string(offset):
> +    #0x08 NameOp NameString DataRef
> +    if (aml[offset] != 0x08):
> +        die( "Name offset 0x%x: expected 0x08 actual 0x%x" %
> +             (offset, aml[offset]));
> +    offset += 1
> +    # Block Name Modifier. Skip it.
> +    if (aml[offset] == 0x5c or aml[offset] == 0x5e):
> +        offset += 1
> +    return offset;
> +
> +# Given data offset, find dword const offset
> +def aml_data_dword_const(offset):
> +    #0x08 NameOp NameString DataRef
> +    if (aml[offset] != 0x0C):
> +        die( "Name offset 0x%x: expected 0x0C actual 0x%x" %
> +             (offset, aml[offset]));
> +    return offset + 1;
> +
> +# Given data offset, find word const offset
> +def aml_data_word_const(offset):
> +    #0x08 NameOp NameString DataRef
> +    if (aml[offset] != 0x0B):
> +        die( "Name offset 0x%x: expected 0x0B actual 0x%x" %
> +             (offset, aml[offset]));
> +    return offset + 1;
> +
> +# Given data offset, find byte const offset
> +def aml_data_byte_const(offset):
> +    #0x08 NameOp NameString DataRef
> +    if (aml[offset] != 0x0A):
> +        die( "Name offset 0x%x: expected 0x0A actual 0x%x" %
> +             (offset, aml[offset]));
> +    return offset + 1;
> +
> +# Given name offset, find dword const offset
> +def aml_name_dword_const(offset):
> +    return aml_data_dword_const(aml_name_string(offset) + 4)
> +
> +# Given name offset, find word const offset
> +def aml_name_word_const(offset):
> +    return aml_data_word_const(aml_name_string(offset) + 4)
> +
> +# Given name offset, find byte const offset
> +def aml_name_byte_const(offset):
> +    return aml_data_byte_const(aml_name_string(offset) + 4)
> +
> +def aml_processor_start(offset):
> +    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
> +    if ((aml[offset] != 0x5B) or (aml[offset + 1] != 0x83)):
> +        die( "Name offset 0x%x: expected 0x5B 0x83 actual 0x%x 0x%x" %
> +             (offset, aml[offset], aml[offset + 1]));
> +    return offset
> +
> +def aml_processor_string(offset):
> +    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
> +    start = aml_processor_start(offset)
> +    offset += 2
> +    pkglenbytes = aml_pkglen_bytes(offset)
> +    offset += pkglenbytes
> +    return offset
> +
> +def aml_processor_end(offset):
> +    start = aml_processor_start(offset)
> +    offset += 2
> +    pkglenbytes = aml_pkglen_bytes(offset)
> +    pkglen = aml_pkglen(offset)
> +    return offset + pkglen
> +
> +def aml_package_start(offset):
> +    offset = aml_name_string(offset) + 4
> +    # 0x12 PkgLength NumElements PackageElementList
> +    if (aml[offset] != 0x12):
> +        die( "Name offset 0x%x: expected 0x12 actual 0x%x" %
> +             (offset, aml[offset]));
> +    offset += 1
> +    return offset + aml_pkglen_bytes(offset) + 1
> +
> +lineno = 0
> +for line in fileinput.input():
> +    # Strip trailing newline
> +    line = line.rstrip();
> +    # line number and debug string to output in case of errors
> +    lineno = lineno + 1
> +    debug = "input line %d: %s" % (lineno, line)
> +    #ASL listing: space, then line#, then ...., then code
> +    pasl = re.compile('^\s+([0-9]+)\.\.\.\.\s*')
> +    m = pasl.search(line)
> +    if (m):
> +        add_asl(lineno, pasl.sub("", line));
> +    # AML listing: offset in hex, then ...., then code
> +    paml = re.compile('^([0-9A-Fa-f]+)\.\.\.\.\s*')
> +    m = paml.search(line)
> +    if (m):
> +        add_aml(m.group(1), paml.sub("", line))
> +
> +# Now go over code
> +# Track AML offset of a previous non-empty ASL command
> +prev_aml_offset = -1
> +for i in range(len(asl)):
> +    debug = "input line %d: %s" % (asl[i].lineno, asl[i].line)
> +
> +    l = asl[i].line
> +
> +    # skip if not an extract directive
> +    a = len(re.findall(r'ACPI_EXTRACT', l))
> +    if (not a):
> +        # If not empty, store AML offset. Will be used for sanity checks
> +        # IASL seems to put {}. at random places in the listing.
> +        # Ignore any non-words for the purpose of this test.
> +        m = re.search(r'\w+', l)
> +        if (m):
> +                prev_aml_offset = asl[i].aml_offset
> +        continue
> +
> +    if (a > 1):
> +        die("Expected at most one ACPI_EXTRACT per line, actual %d" % a)
> +
> +    mext = re.search(r'''
> +                      ^\s* # leading whitespace
> +                      /\*\s* # start C comment
> +                      (ACPI_EXTRACT_\w+) # directive: group(1)
> +                      \s+ # whitspace separates directive from array name
> +                      (\w+) # array name: group(2)
> +                      \s*\*/ # end of C comment
> +                      \s*$ # trailing whitespace
> +                      ''', l, re.VERBOSE)
> +    if (not mext):
> +        die("Stray ACPI_EXTRACT in input")
> +
> +    # previous command must have produced some AML,
> +    # otherwise we are in a middle of a block
> +    if (prev_aml_offset == asl[i].aml_offset):
> +        die("ACPI_EXTRACT directive in the middle of a block")
> +
> +    directive = mext.group(1)
> +    array = mext.group(2)
> +    offset = asl[i].aml_offset
> +
> +    if (directive == "ACPI_EXTRACT_ALL_CODE"):
> +        if array in output:
> +            die("%s directive used more than once" % directive)
> +        output[array] = aml
> +        continue
> +    if (directive == "ACPI_EXTRACT_NAME_DWORD_CONST"):
> +        offset = aml_name_dword_const(offset)
> +    elif (directive == "ACPI_EXTRACT_NAME_WORD_CONST"):
> +        offset = aml_name_word_const(offset)
> +    elif (directive == "ACPI_EXTRACT_NAME_BYTE_CONST"):
> +        offset = aml_name_byte_const(offset)
> +    elif (directive == "ACPI_EXTRACT_NAME_STRING"):
> +        offset = aml_name_string(offset)
> +    elif (directive == "ACPI_EXTRACT_METHOD_STRING"):
> +        offset = aml_method_string(offset)
> +    elif (directive == "ACPI_EXTRACT_PROCESSOR_START"):
> +        offset = aml_processor_start(offset)
> +    elif (directive == "ACPI_EXTRACT_PROCESSOR_STRING"):
> +        offset = aml_processor_string(offset)
> +    elif (directive == "ACPI_EXTRACT_PROCESSOR_END"):
> +        offset = aml_processor_end(offset)
> +    elif (directive == "ACPI_EXTRACT_PKG_START"):
> +        offset = aml_package_start(offset)
> +    else:
> +        die("Unsupported directive %s" % directive)
> +
> +    if array not in output:
> +        output[array] = []
> +    output[array].append(offset)
> +
> +debug = "at end of file"
> +
> +def get_value_type(maxvalue):
> +    #Use type large enough to fit the table
> +    if (maxvalue >= 0x10000):
> +            return "int"
> +    elif (maxvalue >= 0x100):
> +            return "short"
> +    else:
> +            return "char"
> +
> +# Pretty print output
> +for array in output.keys():
> +    otype = get_value_type(max(output[array]))
> +    odata = []
> +    for value in output[array]:
> +        odata.append("0x%x" % value)
> +    sys.stdout.write("unsigned %s %s[] = {\n" % (otype, array))
> +    sys.stdout.write(",\n".join(odata))
> +    sys.stdout.write('\n};\n');
> diff -urN hvmloader/tools/acpi_extract_preprocess.py hvmloader_new//tools/acpi_extract_preprocess.py
> --- hvmloader/tools/acpi_extract_preprocess.py	1970-01-01 08:00:00.000000000 +0800
> +++ hvmloader_new//tools/acpi_extract_preprocess.py	2013-10-16 11:46:53.000000000 +0800
> @@ -0,0 +1,41 @@
> +#!/usr/bin/python
> +# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
> +#
> +# This file may be distributed under the terms of the GNU GPLv3 license.
> +
> +# Read a preprocessed ASL listing and put each ACPI_EXTRACT
> +# directive in a comment, to make iasl skip it.
> +# We also put each directive on a new line, the machinery
> +# in tools/acpi_extract.py requires this.
> +
> +import re;
> +import sys;
> +import fileinput;
> +
> +def die(diag):
> +    sys.stderr.write("Error: %s\n" % (diag))
> +    sys.exit(1)
> +
> +# Note: () around pattern make split return matched string as part of list
> +psplit = re.compile(r''' (
> +                          \b # At word boundary
> +                          ACPI_EXTRACT_\w+ # directive
> +                          \s+ # some whitespace
> +                          \w+ # array name
> +                         )''', re.VERBOSE);
> +
> +lineno = 0
> +for line in fileinput.input():
> +    # line number and debug string to output in case of errors
> +    lineno = lineno + 1
> +    debug = "input line %d: %s" % (lineno, line.rstrip())
> +
> +    s = psplit.split(line);
> +    # The way split works, each odd item is the matching ACPI_EXTRACT directive.
> +    # Put each in a comment, and on a line by itself.
> +    for i in range(len(s)):
> +        if (i % 2):
> +            sys.stdout.write("\n/* %s */\n" % s[i])
> +        else:
> +            sys.stdout.write(s[i])
> +
> 
> Best regards,
> -Gonglei
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xen.org
> http://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
  2013-10-16  6:30 [Qemu-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching Gonglei (Arei)
  2013-10-16  9:13 ` Fabio Fantoni
  2013-10-16  9:13 ` [Qemu-devel] " Fabio Fantoni
@ 2013-10-16  9:19 ` Ian Campbell
  2013-10-16  9:19 ` [Qemu-devel] [Xen-devel] " Ian Campbell
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 38+ messages in thread
From: Ian Campbell @ 2013-10-16  9:19 UTC (permalink / raw)
  To: Gonglei (Arei)
  Cc: Hanweidong (Randy),
	Stefano Stabellini, Yanqiangjun, Luonengjun, qemu-devel,
	xen-devel, Fabio Fantoni, anthony.perard, Gaowei (UVP),
	Huangweidong (Hardware)

On Wed, 2013-10-16 at 06:30 +0000, Gonglei (Arei) wrote:
> http://lists.xen.org/archives/html/xen-devel/2013-09/msg03113.html
> As said above, In Xen platform, after using upstream qemu, all pci devices can be unpluged in the windows guest.
> In this situation, the windows guest may occur blue screen when VM' user click the icon of pass-through Graphics card for trying to unplug the device.
> 
> The kvm system doesn't have this problem for the use of seabios.
> http://www.seabios.org/pipermail/seabios/2011-September/002293.html
> The patch above in seabios solves the problem. The patch is ported in hvmloader and works well.
> 
> This is done by runtime patching:
> - Rename _EJ0 methods for PCI slots in DSDT to EJ0_:
>   note that this has the same checksum, but
>   is ignored by OSPM.
> - At compile time, look for these methods in ASL source,
>   find the matching AML, and store the offsets of these methods
>   in a table named aml_ej0_data.
> - At run time, go over aml_ej0_data, check which slots 
>   not support hotplug and patch the ACPI table, replacing _EJ0 with EJ0_.

This needs a Signed-off-by, see
http://wiki.xen.org/wiki/Submitting_Xen_Patches for what this means you
are agreeing to.

> The files *.py are from seabios

Which is GPLv3 only AFAIK and therefore we need to think carefully about
whether this is acceptable in the Xen code base.

I think it is OK for a compile time only component. What do others
think?

> diff -urN hvmloader/acpi/Makefile hvmloader_new//acpi/Makefile
> --- hvmloader/acpi/Makefile	2013-10-16 11:51:53.000000000 +0800
> +++ hvmloader_new//acpi/Makefile	2013-10-16 11:51:58.000000000 +0800
> @@ -36,18 +36,34 @@
>  
>  dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
>  	awk 'NR > 1 {print s} {s=$$0}' $< > $@
> -	./mk_dsdt --dm-version qemu-xen >> $@
> +	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@
> +	./mk_dsdt --dm-version qemu-xen >> $@	
> +	sed -i 's/aml_ej0_name/dsdt_anycpu_qemu_xen_aml_ej0_name/g' $@
> +	sed -i 's/aml_adr_dword/dsdt_anycpu_qemu_xen_aml_adr_dword/g' $@
>  
>  # NB. awk invocation is a portable alternative to 'head -n -1'
>  dsdt_%cpu.asl: dsdt.asl mk_dsdt
>  	awk 'NR > 1 {print s} {s=$$0}' $< > $@
> +	sed -i 's/AmlCode/dsdt_$*cpu/g' $@
>  	./mk_dsdt --maxcpu $*  >> $@
>  
>  $(filter dsdt_%.c,$(C_SRC)): %.c: iasl %.asl
> -	iasl -vs -p $* -tc $*.asl
> -	sed -e 's/AmlCode/$*/g' $*.hex >$@
> +	cpp -P $*.asl > $*.asl.i.orig
> +	/usr/bin/python ../tools/acpi_extract_preprocess.py $*.asl.i.orig > $*.asl.i
> +	iasl -vs -l -tc -p $* $*.asl.i
> +	/usr/bin/python ../tools/acpi_extract.py $*.lst > $@
>  	echo "int $*_len=sizeof($*);" >>$@
> -	rm -f $*.aml $*.hex
> +	rm -f $*.aml $*.hex $*.asl.i.orig $*.asl.i $*.lst
> +
> +dsdt_anycpu_qemu_xen.c:iasl dsdt_anycpu_qemu_xen.asl
> +	cpp -P $*.asl > $*.asl.i.orig
> +	/usr/bin/python ../tools/acpi_extract_preprocess.py $*.asl.i.orig > $*.asl.i
> +	iasl -vs -l -tc -p $* $*.asl.i
> +	/usr/bin/python ../tools/acpi_extract.py $*.lst > $@
> +	echo "int $*_len=sizeof($*);" >>$@
> +	echo "int $*_aml_ej0_name_len=sizeof($*_aml_ej0_name);" >>$@
> +	echo "int $*_aml_adr_dword_len=sizeof($*_aml_adr_dword);" >>$@
> +	rm -f $*.aml $*.hex $*.asl.i.orig $*.asl.i $*.lst
>  
>  iasl:
>  	@echo
> @@ -64,7 +80,7 @@
>  
>  clean:
>  	rm -rf *.a *.o $(IASL_VER) $(IASL_VER).tar.gz $(DEPS)
> -	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl
> +	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl *.asl.i *.asl.i.orig *.lst
>  
>  install: all
>  
> diff -urN hvmloader/acpi/acpi2_0.h hvmloader_new//acpi/acpi2_0.h
> --- hvmloader/acpi/acpi2_0.h	2013-10-16 11:54:49.000000000 +0800
> +++ hvmloader_new//acpi/acpi2_0.h	2013-10-16 11:46:52.000000000 +0800
> @@ -396,6 +396,11 @@
>      int dsdt_anycpu_len;
>      unsigned char *dsdt_15cpu;
>      int dsdt_15cpu_len;
> +    unsigned short *aml_ej0_name;
> +    unsigned short *aml_adr_dword;
> +    int aml_ej0_name_len;
> +    int aml_adr_dword_len;
> +    
>  };
>  
>  void acpi_build_tables(struct acpi_config *config, unsigned int physical);
> diff -urN hvmloader/acpi/build.c hvmloader_new//acpi/build.c
> --- hvmloader/acpi/build.c	2013-10-16 11:55:55.000000000 +0800
> +++ hvmloader_new//acpi/build.c	2013-10-16 11:46:52.000000000 +0800
> @@ -30,6 +30,9 @@
>  #define align16(sz)        (((sz) + 15) & ~15)
>  #define fixed_strcpy(d, s) strncpy((d), (s), sizeof(d))
>  
> +
> +#define PCI_RMV_BASE 0xae0c
> +
>  extern struct acpi_20_rsdp Rsdp;
>  extern struct acpi_20_rsdt Rsdt;
>  extern struct acpi_20_xsdt Xsdt;
> @@ -404,6 +407,7 @@
>      unsigned char       *dsdt;
>      unsigned long        secondary_tables[ACPI_MAX_SECONDARY_TABLES];
>      int                  nr_secondaries, i;
> +    unsigned int rmvc_pcrm = 0;
>  
>      /* Allocate and initialise the acpi info area. */
>      mem_hole_populate_ram(ACPI_INFO_PHYSICAL_ADDRESS >> PAGE_SHIFT, 1);
> @@ -438,9 +442,26 @@
>          dsdt = mem_alloc(config->dsdt_anycpu_len, 16);
>          if (!dsdt) goto oom;
>          memcpy(dsdt, config->dsdt_anycpu, config->dsdt_anycpu_len);
> -        nr_processor_objects = HVM_MAX_VCPUS;
> +    if(config->aml_adr_dword_len && config->aml_ej0_name_len &&
> +        (config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]) == config->aml_ej0_name_len/sizeof(config->aml_ej0_name[0])))
> +    {
> +         rmvc_pcrm = inl(PCI_RMV_BASE); 
> +	  printf("rmvc_pcrm is %x\n", rmvc_pcrm);
> +        for(i = 0;  i < config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]); i ++)
> +        {
> +            /* Slot is in byte 2 in _ADR */
> +            unsigned char slot = dsdt[config->aml_adr_dword[i] + 2] & 0x1F;
> +            /* Sanity check */
> +            if (memcmp(dsdt + config->aml_ej0_name[i], "_EJ0", 4)) {
> +                goto oom;
> +            }
> +            if (!(rmvc_pcrm & (0x1 << slot))) {
> +                memcpy(dsdt + config->aml_ej0_name[i], "EJ0_", 4);
> +            }
> +        }
>      }
>  
> +    nr_processor_objects = HVM_MAX_VCPUS;
>      /*
>       * N.B. ACPI 1.0 operating systems may not handle FADT with revision 2
>       * or above properly, notably Windows 2000, which tries to copy FADT
> diff -urN hvmloader/acpi/dsdt.asl hvmloader_new//acpi/dsdt.asl
> --- hvmloader/acpi/dsdt.asl	2013-10-16 11:56:20.000000000 +0800
> +++ hvmloader_new//acpi/dsdt.asl	2013-10-16 11:46:52.000000000 +0800
> @@ -16,6 +16,7 @@
>   * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
>   * Place - Suite 330, Boston, MA 02111-1307 USA.
>   */
> +ACPI_EXTRACT_ALL_CODE AmlCode
>  
>  DefinitionBlock ("DSDT.aml", "DSDT", 2, "Xen", "HVM", 0)
>  {
> diff -urN hvmloader/acpi/mk_dsdt.c hvmloader_new//acpi/mk_dsdt.c
> --- hvmloader/acpi/mk_dsdt.c	2013-10-16 11:56:32.000000000 +0800
> +++ hvmloader_new//acpi/mk_dsdt.c	2013-10-16 11:46:52.000000000 +0800
> @@ -368,7 +368,9 @@
>          /* hotplug_slot */
>          for (slot = 1; slot <= 31; slot++) {
>              push_block("Device", "S%i", slot); {
> +                printf("ACPI_EXTRACT_NAME_DWORD_CONST aml_adr_dword\n");
>                  stmt("Name", "_ADR, %#06x0000", slot);
> +                printf("ACPI_EXTRACT_METHOD_STRING aml_ej0_name\n");
>                  push_block("Method", "_EJ0,1"); {
>                      stmt("Store", "ShiftLeft(1, %#06x), B0EJ", slot);
>                      stmt("Return", "0x0");
> @@ -453,7 +455,7 @@
>  /*
>   * Local variables:
>   * mode: C
> - * c-file-style: "BSD"
> + * c-set-style: "BSD"
>   * c-basic-offset: 4
>   * tab-width: 4
>   * indent-tabs-mode: nil
> diff -urN hvmloader/ovmf.c hvmloader_new//ovmf.c
> --- hvmloader/ovmf.c	2013-10-16 11:57:15.000000000 +0800
> +++ hvmloader_new//ovmf.c	2013-10-16 11:57:48.000000000 +0800
> @@ -79,7 +79,11 @@
>          .dsdt_anycpu = dsdt_anycpu,
>          .dsdt_anycpu_len = dsdt_anycpu_len,
>          .dsdt_15cpu = NULL, 
> -        .dsdt_15cpu_len = 0
> +        .dsdt_15cpu_len = 0,
> +        .aml_ej0_name = NULL,
> +        .aml_adr_dword = NULL,
> +        .aml_ej0_name_len = 0,
> +        .aml_adr_dword_len = 0,
>      };
>  
>      acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
> diff -urN hvmloader/rombios.c hvmloader_new//rombios.c
> --- hvmloader/rombios.c	2013-10-16 11:57:15.000000000 +0800
> +++ hvmloader_new//rombios.c	2013-10-16 11:57:48.000000000 +0800
> @@ -179,6 +179,10 @@
>          .dsdt_anycpu_len = dsdt_anycpu_len,
>          .dsdt_15cpu = dsdt_15cpu,
>          .dsdt_15cpu_len = dsdt_15cpu_len,
> +        .aml_ej0_name = NULL,
> +        .aml_adr_dword = NULL,
> +        .aml_ej0_name_len = 0,
> +        .aml_adr_dword_len = 0,
>      };
>  
>      acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
> diff -urN hvmloader/seabios.c hvmloader_new//seabios.c
> --- hvmloader/seabios.c	2013-10-16 11:57:15.000000000 +0800
> +++ hvmloader_new//seabios.c	2013-10-16 11:57:48.000000000 +0800
> @@ -33,6 +33,10 @@
>  
>  extern unsigned char dsdt_anycpu_qemu_xen[];
>  extern int dsdt_anycpu_qemu_xen_len;
> +extern unsigned short dsdt_anycpu_qemu_xen_aml_ej0_name[];
> +extern unsigned short dsdt_anycpu_qemu_xen_aml_adr_dword[];
> +extern int dsdt_anycpu_qemu_xen_aml_ej0_name_len;
> +extern int dsdt_anycpu_qemu_xen_aml_adr_dword_len;
>  
>  struct seabios_info {
>      char signature[14]; /* XenHVMSeaBIOS\0 */
> @@ -99,6 +103,10 @@
>          .dsdt_anycpu_len = dsdt_anycpu_qemu_xen_len,
>          .dsdt_15cpu = NULL,
>          .dsdt_15cpu_len = 0,
> +        .aml_ej0_name = dsdt_anycpu_qemu_xen_aml_ej0_name,
> +        .aml_adr_dword = dsdt_anycpu_qemu_xen_aml_adr_dword,
> +        .aml_ej0_name_len = dsdt_anycpu_qemu_xen_aml_ej0_name_len,
> +        .aml_adr_dword_len = dsdt_anycpu_qemu_xen_aml_adr_dword_len,
>      };
>  
>      acpi_build_tables(&config, rsdp);
> diff -urN hvmloader/tools/acpi_extract.py hvmloader_new//tools/acpi_extract.py
> --- hvmloader/tools/acpi_extract.py	1970-01-01 08:00:00.000000000 +0800
> +++ hvmloader_new//tools/acpi_extract.py	2013-10-16 11:46:52.000000000 +0800
> @@ -0,0 +1,308 @@
> +#!/usr/bin/python
> +# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
> +#
> +# This file may be distributed under the terms of the GNU GPLv3 license.
> +
> +# Process mixed ASL/AML listing (.lst file) produced by iasl -l
> +# Locate and execute ACPI_EXTRACT directives, output offset info
> +# 
> +# Documentation of ACPI_EXTRACT_* directive tags:
> +# 
> +# These directive tags output offset information from AML for BIOS runtime
> +# table generation.
> +# Each directive is of the form:
> +# ACPI_EXTRACT_<TYPE> <array_name> <Operator> (...)
> +# and causes the extractor to create an array
> +# named <array_name> with offset, in the generated AML,
> +# of an object of a given type in the following <Operator>.
> +# 
> +# A directive must fit on a single code line.
> +# 
> +# Object type in AML is verified, a mismatch causes a build failure.
> +# 
> +# Directives and operators currently supported are:
> +# ACPI_EXTRACT_NAME_DWORD_CONST - extract a Dword Const object from Name()
> +# ACPI_EXTRACT_NAME_WORD_CONST - extract a Word Const object from Name()
> +# ACPI_EXTRACT_NAME_BYTE_CONST - extract a Byte Const object from Name()
> +# ACPI_EXTRACT_METHOD_STRING - extract a NameString from Method()
> +# ACPI_EXTRACT_NAME_STRING - extract a NameString from Name()
> +# ACPI_EXTRACT_PROCESSOR_START - start of Processor() block
> +# ACPI_EXTRACT_PROCESSOR_STRING - extract a NameString from Processor()
> +# ACPI_EXTRACT_PROCESSOR_END - offset at last byte of Processor() + 1
> +# ACPI_EXTRACT_PKG_START - start of Package block
> +#
> +# ACPI_EXTRACT_ALL_CODE - create an array storing the generated AML bytecode
> +# 
> +# ACPI_EXTRACT is not allowed anywhere else in code, except in comments.
> +
> +import re;
> +import sys;
> +import fileinput;
> +
> +aml = []
> +asl = []
> +output = {}
> +debug = ""
> +
> +class asl_line:
> +    line = None
> +    lineno = None
> +    aml_offset = None
> +
> +def die(diag):
> +    sys.stderr.write("Error: %s; %s\n" % (diag, debug))
> +    sys.exit(1)
> +    
> +#Store an ASL command, matching AML offset, and input line (for debugging)
> +def add_asl(lineno, line):
> +    l = asl_line()
> +    l.line = line
> +    l.lineno = lineno
> +    l.aml_offset = len(aml)
> +    asl.append(l)
> +
> +#Store an AML byte sequence
> +#Verify that offset output by iasl matches # of bytes so far
> +def add_aml(offset, line):
> +    o = int(offset, 16);
> +    # Sanity check: offset must match size of code so far
> +    if (o != len(aml)):
> +        die("Offset 0x%x != 0x%x" % (o, len(aml)))
> +    # Strip any trailing dots and ASCII dump after "
> +    line = re.sub(r'\s*\.*\s*".*$',"", line)
> +    # Strip traling whitespace
> +    line = re.sub(r'\s+$',"", line)
> +    # Strip leading whitespace
> +    line = re.sub(r'^\s+',"", line)
> +    # Split on whitespace
> +    code = re.split(r'\s+', line)
> +    for c in code:
> +        # Require a legal hex number, two digits
> +        if (not(re.search(r'^[0-9A-Fa-f][0-9A-Fa-f]$', c))):
> +            die("Unexpected octet %s" % c);
> +        aml.append(int(c, 16));
> +
> +# Process aml bytecode array, decoding AML
> +def aml_pkglen_bytes(offset):
> +    # PkgLength can be multibyte. Bits 8-7 give the # of extra bytes.
> +    pkglenbytes = aml[offset] >> 6;
> +    return pkglenbytes + 1
> +
> +def aml_pkglen(offset):
> +    pkgstart = offset
> +    pkglenbytes = aml_pkglen_bytes(offset)
> +    pkglen = aml[offset] & 0x3F
> +    # If multibyte, first nibble only uses bits 0-3
> +    if ((pkglenbytes > 0) and (pkglen & 0x30)):
> +        die("PkgLen bytes 0x%x but first nibble 0x%x expected 0x0X" %
> +            (pkglen, pkglen))
> +    offset += 1
> +    pkglenbytes -= 1
> +    for i in range(pkglenbytes):
> +        pkglen |= aml[offset + i] << (i * 8 + 4)
> +    if (len(aml) < pkgstart + pkglen):
> +        die("PckgLen 0x%x at offset 0x%x exceeds AML size 0x%x" %
> +            (pkglen, offset, len(aml)))
> +    return pkglen
> +
> +# Given method offset, find its NameString offset
> +def aml_method_string(offset):
> +    #0x14 MethodOp PkgLength NameString MethodFlags TermList
> +    if (aml[offset] != 0x14):
> +        die( "Method offset 0x%x: expected 0x14 actual 0x%x" %
> +             (offset, aml[offset]));
> +    offset += 1;
> +    pkglenbytes = aml_pkglen_bytes(offset)
> +    offset += pkglenbytes;
> +    return offset;
> +
> +# Given name offset, find its NameString offset
> +def aml_name_string(offset):
> +    #0x08 NameOp NameString DataRef
> +    if (aml[offset] != 0x08):
> +        die( "Name offset 0x%x: expected 0x08 actual 0x%x" %
> +             (offset, aml[offset]));
> +    offset += 1
> +    # Block Name Modifier. Skip it.
> +    if (aml[offset] == 0x5c or aml[offset] == 0x5e):
> +        offset += 1
> +    return offset;
> +
> +# Given data offset, find dword const offset
> +def aml_data_dword_const(offset):
> +    #0x08 NameOp NameString DataRef
> +    if (aml[offset] != 0x0C):
> +        die( "Name offset 0x%x: expected 0x0C actual 0x%x" %
> +             (offset, aml[offset]));
> +    return offset + 1;
> +
> +# Given data offset, find word const offset
> +def aml_data_word_const(offset):
> +    #0x08 NameOp NameString DataRef
> +    if (aml[offset] != 0x0B):
> +        die( "Name offset 0x%x: expected 0x0B actual 0x%x" %
> +             (offset, aml[offset]));
> +    return offset + 1;
> +
> +# Given data offset, find byte const offset
> +def aml_data_byte_const(offset):
> +    #0x08 NameOp NameString DataRef
> +    if (aml[offset] != 0x0A):
> +        die( "Name offset 0x%x: expected 0x0A actual 0x%x" %
> +             (offset, aml[offset]));
> +    return offset + 1;
> +
> +# Given name offset, find dword const offset
> +def aml_name_dword_const(offset):
> +    return aml_data_dword_const(aml_name_string(offset) + 4)
> +
> +# Given name offset, find word const offset
> +def aml_name_word_const(offset):
> +    return aml_data_word_const(aml_name_string(offset) + 4)
> +
> +# Given name offset, find byte const offset
> +def aml_name_byte_const(offset):
> +    return aml_data_byte_const(aml_name_string(offset) + 4)
> +
> +def aml_processor_start(offset):
> +    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
> +    if ((aml[offset] != 0x5B) or (aml[offset + 1] != 0x83)):
> +        die( "Name offset 0x%x: expected 0x5B 0x83 actual 0x%x 0x%x" %
> +             (offset, aml[offset], aml[offset + 1]));
> +    return offset
> +
> +def aml_processor_string(offset):
> +    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
> +    start = aml_processor_start(offset)
> +    offset += 2
> +    pkglenbytes = aml_pkglen_bytes(offset)
> +    offset += pkglenbytes
> +    return offset
> +
> +def aml_processor_end(offset):
> +    start = aml_processor_start(offset)
> +    offset += 2
> +    pkglenbytes = aml_pkglen_bytes(offset)
> +    pkglen = aml_pkglen(offset)
> +    return offset + pkglen
> +
> +def aml_package_start(offset):
> +    offset = aml_name_string(offset) + 4
> +    # 0x12 PkgLength NumElements PackageElementList
> +    if (aml[offset] != 0x12):
> +        die( "Name offset 0x%x: expected 0x12 actual 0x%x" %
> +             (offset, aml[offset]));
> +    offset += 1
> +    return offset + aml_pkglen_bytes(offset) + 1
> +
> +lineno = 0
> +for line in fileinput.input():
> +    # Strip trailing newline
> +    line = line.rstrip();
> +    # line number and debug string to output in case of errors
> +    lineno = lineno + 1
> +    debug = "input line %d: %s" % (lineno, line)
> +    #ASL listing: space, then line#, then ...., then code
> +    pasl = re.compile('^\s+([0-9]+)\.\.\.\.\s*')
> +    m = pasl.search(line)
> +    if (m):
> +        add_asl(lineno, pasl.sub("", line));
> +    # AML listing: offset in hex, then ...., then code
> +    paml = re.compile('^([0-9A-Fa-f]+)\.\.\.\.\s*')
> +    m = paml.search(line)
> +    if (m):
> +        add_aml(m.group(1), paml.sub("", line))
> +
> +# Now go over code
> +# Track AML offset of a previous non-empty ASL command
> +prev_aml_offset = -1
> +for i in range(len(asl)):
> +    debug = "input line %d: %s" % (asl[i].lineno, asl[i].line)
> +
> +    l = asl[i].line
> +
> +    # skip if not an extract directive
> +    a = len(re.findall(r'ACPI_EXTRACT', l))
> +    if (not a):
> +        # If not empty, store AML offset. Will be used for sanity checks
> +        # IASL seems to put {}. at random places in the listing.
> +        # Ignore any non-words for the purpose of this test.
> +        m = re.search(r'\w+', l)
> +        if (m):
> +                prev_aml_offset = asl[i].aml_offset
> +        continue
> +
> +    if (a > 1):
> +        die("Expected at most one ACPI_EXTRACT per line, actual %d" % a)
> +
> +    mext = re.search(r'''
> +                      ^\s* # leading whitespace
> +                      /\*\s* # start C comment
> +                      (ACPI_EXTRACT_\w+) # directive: group(1)
> +                      \s+ # whitspace separates directive from array name
> +                      (\w+) # array name: group(2)
> +                      \s*\*/ # end of C comment
> +                      \s*$ # trailing whitespace
> +                      ''', l, re.VERBOSE)
> +    if (not mext):
> +        die("Stray ACPI_EXTRACT in input")
> +
> +    # previous command must have produced some AML,
> +    # otherwise we are in a middle of a block
> +    if (prev_aml_offset == asl[i].aml_offset):
> +        die("ACPI_EXTRACT directive in the middle of a block")
> +
> +    directive = mext.group(1)
> +    array = mext.group(2)
> +    offset = asl[i].aml_offset
> +
> +    if (directive == "ACPI_EXTRACT_ALL_CODE"):
> +        if array in output:
> +            die("%s directive used more than once" % directive)
> +        output[array] = aml
> +        continue
> +    if (directive == "ACPI_EXTRACT_NAME_DWORD_CONST"):
> +        offset = aml_name_dword_const(offset)
> +    elif (directive == "ACPI_EXTRACT_NAME_WORD_CONST"):
> +        offset = aml_name_word_const(offset)
> +    elif (directive == "ACPI_EXTRACT_NAME_BYTE_CONST"):
> +        offset = aml_name_byte_const(offset)
> +    elif (directive == "ACPI_EXTRACT_NAME_STRING"):
> +        offset = aml_name_string(offset)
> +    elif (directive == "ACPI_EXTRACT_METHOD_STRING"):
> +        offset = aml_method_string(offset)
> +    elif (directive == "ACPI_EXTRACT_PROCESSOR_START"):
> +        offset = aml_processor_start(offset)
> +    elif (directive == "ACPI_EXTRACT_PROCESSOR_STRING"):
> +        offset = aml_processor_string(offset)
> +    elif (directive == "ACPI_EXTRACT_PROCESSOR_END"):
> +        offset = aml_processor_end(offset)
> +    elif (directive == "ACPI_EXTRACT_PKG_START"):
> +        offset = aml_package_start(offset)
> +    else:
> +        die("Unsupported directive %s" % directive)
> +
> +    if array not in output:
> +        output[array] = []
> +    output[array].append(offset)
> +
> +debug = "at end of file"
> +
> +def get_value_type(maxvalue):
> +    #Use type large enough to fit the table
> +    if (maxvalue >= 0x10000):
> +            return "int"
> +    elif (maxvalue >= 0x100):
> +            return "short"
> +    else:
> +            return "char"
> +
> +# Pretty print output
> +for array in output.keys():
> +    otype = get_value_type(max(output[array]))
> +    odata = []
> +    for value in output[array]:
> +        odata.append("0x%x" % value)
> +    sys.stdout.write("unsigned %s %s[] = {\n" % (otype, array))
> +    sys.stdout.write(",\n".join(odata))
> +    sys.stdout.write('\n};\n');
> diff -urN hvmloader/tools/acpi_extract_preprocess.py hvmloader_new//tools/acpi_extract_preprocess.py
> --- hvmloader/tools/acpi_extract_preprocess.py	1970-01-01 08:00:00.000000000 +0800
> +++ hvmloader_new//tools/acpi_extract_preprocess.py	2013-10-16 11:46:53.000000000 +0800
> @@ -0,0 +1,41 @@
> +#!/usr/bin/python
> +# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
> +#
> +# This file may be distributed under the terms of the GNU GPLv3 license.
> +
> +# Read a preprocessed ASL listing and put each ACPI_EXTRACT
> +# directive in a comment, to make iasl skip it.
> +# We also put each directive on a new line, the machinery
> +# in tools/acpi_extract.py requires this.
> +
> +import re;
> +import sys;
> +import fileinput;
> +
> +def die(diag):
> +    sys.stderr.write("Error: %s\n" % (diag))
> +    sys.exit(1)
> +
> +# Note: () around pattern make split return matched string as part of list
> +psplit = re.compile(r''' (
> +                          \b # At word boundary
> +                          ACPI_EXTRACT_\w+ # directive
> +                          \s+ # some whitespace
> +                          \w+ # array name
> +                         )''', re.VERBOSE);
> +
> +lineno = 0
> +for line in fileinput.input():
> +    # line number and debug string to output in case of errors
> +    lineno = lineno + 1
> +    debug = "input line %d: %s" % (lineno, line.rstrip())
> +
> +    s = psplit.split(line);
> +    # The way split works, each odd item is the matching ACPI_EXTRACT directive.
> +    # Put each in a comment, and on a line by itself.
> +    for i in range(len(s)):
> +        if (i % 2):
> +            sys.stdout.write("\n/* %s */\n" % s[i])
> +        else:
> +            sys.stdout.write(s[i])
> +
> 
> Best regards,
> -Gonglei
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xen.org
> http://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [Xen-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
  2013-10-16  6:30 [Qemu-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching Gonglei (Arei)
                   ` (3 preceding siblings ...)
  2013-10-16  9:19 ` [Qemu-devel] [Xen-devel] " Ian Campbell
@ 2013-10-16  9:54 ` Jan Beulich
  2013-10-16 10:04   ` Ian Campbell
  2013-10-16 10:04   ` Ian Campbell
  2013-10-16  9:54 ` Jan Beulich
  5 siblings, 2 replies; 38+ messages in thread
From: Jan Beulich @ 2013-10-16  9:54 UTC (permalink / raw)
  To: Gonglei (Arei)
  Cc: Yanqiangjun, Hanweidong (Randy),
	Stefano Stabellini, Luonengjun, qemu-devel, xen-devel,
	Fabio Fantoni, anthony.perard, Gaowei (UVP),
	Huangweidong (Hardware)

>>> On 16.10.13 at 08:30, "Gonglei (Arei)" <arei.gonglei@huawei.com> wrote:
> --- hvmloader/acpi/Makefile	2013-10-16 11:51:53.000000000 +0800
> +++ hvmloader_new//acpi/Makefile	2013-10-16 11:51:58.000000000 +0800
> @@ -36,18 +36,34 @@
>  
>  dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
>  	awk 'NR > 1 {print s} {s=$$0}' $< > $@
> -	./mk_dsdt --dm-version qemu-xen >> $@
> +	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@

This must never be done - if someone hits Ctrl-C in the middle of
this, you'll have a modified but incomplete generated file. You
either need to use properly chained rules, or do all output to a
temporary file which you rename as the last step.

I realize that the problem existed before your change, but you
making it worse requires doing it properly now.

> +	./mk_dsdt --dm-version qemu-xen >> $@	
> +	sed -i 's/aml_ej0_name/dsdt_anycpu_qemu_xen_aml_ej0_name/g' $@
> +	sed -i 's/aml_adr_dword/dsdt_anycpu_qemu_xen_aml_adr_dword/g' $@
>  
>  # NB. awk invocation is a portable alternative to 'head -n -1'
>  dsdt_%cpu.asl: dsdt.asl mk_dsdt
>  	awk 'NR > 1 {print s} {s=$$0}' $< > $@
> +	sed -i 's/AmlCode/dsdt_$*cpu/g' $@
>  	./mk_dsdt --maxcpu $*  >> $@
>  
>  $(filter dsdt_%.c,$(C_SRC)): %.c: iasl %.asl
> -	iasl -vs -p $* -tc $*.asl
> -	sed -e 's/AmlCode/$*/g' $*.hex >$@
> +	cpp -P $*.asl > $*.asl.i.orig
> +	/usr/bin/python ../tools/acpi_extract_preprocess.py $*.asl.i.orig > $*.asl.i
> +	iasl -vs -l -tc -p $* $*.asl.i
> +	/usr/bin/python ../tools/acpi_extract.py $*.lst > $@
>  	echo "int $*_len=sizeof($*);" >>$@
> -	rm -f $*.aml $*.hex
> +	rm -f $*.aml $*.hex $*.asl.i.orig $*.asl.i $*.lst
> +
> +dsdt_anycpu_qemu_xen.c:iasl dsdt_anycpu_qemu_xen.asl
> +	cpp -P $*.asl > $*.asl.i.orig
> +	/usr/bin/python ../tools/acpi_extract_preprocess.py $*.asl.i.orig > $*.asl.i
> +	iasl -vs -l -tc -p $* $*.asl.i
> +	/usr/bin/python ../tools/acpi_extract.py $*.lst > $@
> +	echo "int $*_len=sizeof($*);" >>$@
> +	echo "int $*_aml_ej0_name_len=sizeof($*_aml_ej0_name);" >>$@
> +	echo "int $*_aml_adr_dword_len=sizeof($*_aml_adr_dword);" >>$@

Why is this needed only here, but not in the generic .asl -> .c rule?
Keeping a single, generic rule would be preferred even if the
generated data isn't used for the other cases.

Also, please generate you patches with -p passed to diff (or a
suitable equivalent if you use some other mechanism for
generating it).

Jan

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
  2013-10-16  6:30 [Qemu-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching Gonglei (Arei)
                   ` (4 preceding siblings ...)
  2013-10-16  9:54 ` Jan Beulich
@ 2013-10-16  9:54 ` Jan Beulich
  5 siblings, 0 replies; 38+ messages in thread
From: Jan Beulich @ 2013-10-16  9:54 UTC (permalink / raw)
  To: Gonglei (Arei)
  Cc: Yanqiangjun, Hanweidong (Randy),
	Stefano Stabellini, Luonengjun, qemu-devel, xen-devel,
	Fabio Fantoni, anthony.perard, Gaowei (UVP),
	Huangweidong (Hardware)

>>> On 16.10.13 at 08:30, "Gonglei (Arei)" <arei.gonglei@huawei.com> wrote:
> --- hvmloader/acpi/Makefile	2013-10-16 11:51:53.000000000 +0800
> +++ hvmloader_new//acpi/Makefile	2013-10-16 11:51:58.000000000 +0800
> @@ -36,18 +36,34 @@
>  
>  dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
>  	awk 'NR > 1 {print s} {s=$$0}' $< > $@
> -	./mk_dsdt --dm-version qemu-xen >> $@
> +	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@

This must never be done - if someone hits Ctrl-C in the middle of
this, you'll have a modified but incomplete generated file. You
either need to use properly chained rules, or do all output to a
temporary file which you rename as the last step.

I realize that the problem existed before your change, but you
making it worse requires doing it properly now.

> +	./mk_dsdt --dm-version qemu-xen >> $@	
> +	sed -i 's/aml_ej0_name/dsdt_anycpu_qemu_xen_aml_ej0_name/g' $@
> +	sed -i 's/aml_adr_dword/dsdt_anycpu_qemu_xen_aml_adr_dword/g' $@
>  
>  # NB. awk invocation is a portable alternative to 'head -n -1'
>  dsdt_%cpu.asl: dsdt.asl mk_dsdt
>  	awk 'NR > 1 {print s} {s=$$0}' $< > $@
> +	sed -i 's/AmlCode/dsdt_$*cpu/g' $@
>  	./mk_dsdt --maxcpu $*  >> $@
>  
>  $(filter dsdt_%.c,$(C_SRC)): %.c: iasl %.asl
> -	iasl -vs -p $* -tc $*.asl
> -	sed -e 's/AmlCode/$*/g' $*.hex >$@
> +	cpp -P $*.asl > $*.asl.i.orig
> +	/usr/bin/python ../tools/acpi_extract_preprocess.py $*.asl.i.orig > $*.asl.i
> +	iasl -vs -l -tc -p $* $*.asl.i
> +	/usr/bin/python ../tools/acpi_extract.py $*.lst > $@
>  	echo "int $*_len=sizeof($*);" >>$@
> -	rm -f $*.aml $*.hex
> +	rm -f $*.aml $*.hex $*.asl.i.orig $*.asl.i $*.lst
> +
> +dsdt_anycpu_qemu_xen.c:iasl dsdt_anycpu_qemu_xen.asl
> +	cpp -P $*.asl > $*.asl.i.orig
> +	/usr/bin/python ../tools/acpi_extract_preprocess.py $*.asl.i.orig > $*.asl.i
> +	iasl -vs -l -tc -p $* $*.asl.i
> +	/usr/bin/python ../tools/acpi_extract.py $*.lst > $@
> +	echo "int $*_len=sizeof($*);" >>$@
> +	echo "int $*_aml_ej0_name_len=sizeof($*_aml_ej0_name);" >>$@
> +	echo "int $*_aml_adr_dword_len=sizeof($*_aml_adr_dword);" >>$@

Why is this needed only here, but not in the generic .asl -> .c rule?
Keeping a single, generic rule would be preferred even if the
generated data isn't used for the other cases.

Also, please generate you patches with -p passed to diff (or a
suitable equivalent if you use some other mechanism for
generating it).

Jan

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [Xen-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
  2013-10-16  9:54 ` Jan Beulich
@ 2013-10-16 10:04   ` Ian Campbell
  2013-10-16 10:49     ` Markus Armbruster
  2013-10-16 10:49     ` Markus Armbruster
  2013-10-16 10:04   ` Ian Campbell
  1 sibling, 2 replies; 38+ messages in thread
From: Ian Campbell @ 2013-10-16 10:04 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Stefano Stabellini, Yanqiangjun, Luonengjun, qemu-devel,
	xen-devel, Fabio Fantoni, Gonglei (Arei),
	anthony.perard, Hanweidong (Randy), Gaowei (UVP),
	Huangweidong (Hardware)

On Wed, 2013-10-16 at 10:54 +0100, Jan Beulich wrote:
> >>> On 16.10.13 at 08:30, "Gonglei (Arei)" <arei.gonglei@huawei.com> wrote:
> > --- hvmloader/acpi/Makefile	2013-10-16 11:51:53.000000000 +0800
> > +++ hvmloader_new//acpi/Makefile	2013-10-16 11:51:58.000000000 +0800
> > @@ -36,18 +36,34 @@
> >  
> >  dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
> >  	awk 'NR > 1 {print s} {s=$$0}' $< > $@
> > -	./mk_dsdt --dm-version qemu-xen >> $@
> > +	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@
> 
> This must never be done - if someone hits Ctrl-C in the middle of
> this, you'll have a modified but incomplete generated file. You
> either need to use properly chained rules, or do all output to a
> temporary file which you rename as the last step.
> 
> I realize that the problem existed before your change, but you
> making it worse requires doing it properly now.

The correct way to do this is to generate to a temporary file and then
use $(call move-if-changed,$@.tmp,$@). There are a bunch of examples in
tools/libxl/Makefile and elsewhere.

Ian.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
  2013-10-16  9:54 ` Jan Beulich
  2013-10-16 10:04   ` Ian Campbell
@ 2013-10-16 10:04   ` Ian Campbell
  1 sibling, 0 replies; 38+ messages in thread
From: Ian Campbell @ 2013-10-16 10:04 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Stefano Stabellini, Yanqiangjun, Luonengjun, qemu-devel,
	xen-devel, Fabio Fantoni, Gonglei (Arei),
	anthony.perard, Hanweidong (Randy), Gaowei (UVP),
	Huangweidong (Hardware)

On Wed, 2013-10-16 at 10:54 +0100, Jan Beulich wrote:
> >>> On 16.10.13 at 08:30, "Gonglei (Arei)" <arei.gonglei@huawei.com> wrote:
> > --- hvmloader/acpi/Makefile	2013-10-16 11:51:53.000000000 +0800
> > +++ hvmloader_new//acpi/Makefile	2013-10-16 11:51:58.000000000 +0800
> > @@ -36,18 +36,34 @@
> >  
> >  dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
> >  	awk 'NR > 1 {print s} {s=$$0}' $< > $@
> > -	./mk_dsdt --dm-version qemu-xen >> $@
> > +	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@
> 
> This must never be done - if someone hits Ctrl-C in the middle of
> this, you'll have a modified but incomplete generated file. You
> either need to use properly chained rules, or do all output to a
> temporary file which you rename as the last step.
> 
> I realize that the problem existed before your change, but you
> making it worse requires doing it properly now.

The correct way to do this is to generate to a temporary file and then
use $(call move-if-changed,$@.tmp,$@). There are a bunch of examples in
tools/libxl/Makefile and elsewhere.

Ian.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [Xen-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
  2013-10-16 10:04   ` Ian Campbell
@ 2013-10-16 10:49     ` Markus Armbruster
  2013-10-16 10:58       ` Ian Campbell
  2013-10-16 10:58       ` Ian Campbell
  2013-10-16 10:49     ` Markus Armbruster
  1 sibling, 2 replies; 38+ messages in thread
From: Markus Armbruster @ 2013-10-16 10:49 UTC (permalink / raw)
  To: Ian Campbell
  Cc: Gonglei (Arei),
	Stefano Stabellini, Yanqiangjun, Luonengjun, qemu-devel,
	xen-devel, Fabio Fantoni, Jan Beulich, anthony.perard,
	Hanweidong (Randy), Gaowei (UVP), Huangweidong (Hardware)

Ian Campbell <Ian.Campbell@citrix.com> writes:

> On Wed, 2013-10-16 at 10:54 +0100, Jan Beulich wrote:
>> >>> On 16.10.13 at 08:30, "Gonglei (Arei)" <arei.gonglei@huawei.com> wrote:
>> > --- hvmloader/acpi/Makefile	2013-10-16 11:51:53.000000000 +0800
>> > +++ hvmloader_new//acpi/Makefile	2013-10-16 11:51:58.000000000 +0800
>> > @@ -36,18 +36,34 @@
>> >  
>> >  dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
>> >  	awk 'NR > 1 {print s} {s=$$0}' $< > $@
>> > -	./mk_dsdt --dm-version qemu-xen >> $@
>> > +	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@
>> 
>> This must never be done - if someone hits Ctrl-C in the middle of
>> this, you'll have a modified but incomplete generated file. You
>> either need to use properly chained rules, or do all output to a
>> temporary file which you rename as the last step.
>> 
>> I realize that the problem existed before your change, but you
>> making it worse requires doing it properly now.
>
> The correct way to do this is to generate to a temporary file and then
> use $(call move-if-changed,$@.tmp,$@). There are a bunch of examples in
> tools/libxl/Makefile and elsewhere.

Quoting the GNU make manual[*]:

    So generally the right thing to do is to delete the target file if
    the recipe fails after beginning to change the file.  make will do
    this if .DELETE_ON_ERROR appears as a target.  This is almost always
    what you want make to do, but it is not historical practice; so for
    compatibility, you must explicitly request it.

In my opinion, every Makefile should request it.

[*] https://www.gnu.org/software/make/manual/html_node/Errors.html

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
  2013-10-16 10:04   ` Ian Campbell
  2013-10-16 10:49     ` Markus Armbruster
@ 2013-10-16 10:49     ` Markus Armbruster
  1 sibling, 0 replies; 38+ messages in thread
From: Markus Armbruster @ 2013-10-16 10:49 UTC (permalink / raw)
  To: Ian Campbell
  Cc: Gonglei (Arei),
	Stefano Stabellini, Yanqiangjun, Luonengjun, qemu-devel,
	xen-devel, Fabio Fantoni, Jan Beulich, anthony.perard,
	Hanweidong (Randy), Gaowei (UVP), Huangweidong (Hardware)

Ian Campbell <Ian.Campbell@citrix.com> writes:

> On Wed, 2013-10-16 at 10:54 +0100, Jan Beulich wrote:
>> >>> On 16.10.13 at 08:30, "Gonglei (Arei)" <arei.gonglei@huawei.com> wrote:
>> > --- hvmloader/acpi/Makefile	2013-10-16 11:51:53.000000000 +0800
>> > +++ hvmloader_new//acpi/Makefile	2013-10-16 11:51:58.000000000 +0800
>> > @@ -36,18 +36,34 @@
>> >  
>> >  dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
>> >  	awk 'NR > 1 {print s} {s=$$0}' $< > $@
>> > -	./mk_dsdt --dm-version qemu-xen >> $@
>> > +	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@
>> 
>> This must never be done - if someone hits Ctrl-C in the middle of
>> this, you'll have a modified but incomplete generated file. You
>> either need to use properly chained rules, or do all output to a
>> temporary file which you rename as the last step.
>> 
>> I realize that the problem existed before your change, but you
>> making it worse requires doing it properly now.
>
> The correct way to do this is to generate to a temporary file and then
> use $(call move-if-changed,$@.tmp,$@). There are a bunch of examples in
> tools/libxl/Makefile and elsewhere.

Quoting the GNU make manual[*]:

    So generally the right thing to do is to delete the target file if
    the recipe fails after beginning to change the file.  make will do
    this if .DELETE_ON_ERROR appears as a target.  This is almost always
    what you want make to do, but it is not historical practice; so for
    compatibility, you must explicitly request it.

In my opinion, every Makefile should request it.

[*] https://www.gnu.org/software/make/manual/html_node/Errors.html

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [Xen-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
  2013-10-16 10:49     ` Markus Armbruster
@ 2013-10-16 10:58       ` Ian Campbell
  2013-10-16 11:10         ` Markus Armbruster
  2013-10-16 11:10         ` Markus Armbruster
  2013-10-16 10:58       ` Ian Campbell
  1 sibling, 2 replies; 38+ messages in thread
From: Ian Campbell @ 2013-10-16 10:58 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Gonglei (Arei),
	Stefano Stabellini, Yanqiangjun, Luonengjun, qemu-devel,
	xen-devel, Fabio Fantoni, Jan Beulich, anthony.perard,
	Hanweidong (Randy), Gaowei (UVP), Huangweidong (Hardware)

On Wed, 2013-10-16 at 12:49 +0200, Markus Armbruster wrote:
> Ian Campbell <Ian.Campbell@citrix.com> writes:
> 
> > On Wed, 2013-10-16 at 10:54 +0100, Jan Beulich wrote:
> >> >>> On 16.10.13 at 08:30, "Gonglei (Arei)" <arei.gonglei@huawei.com> wrote:
> >> > --- hvmloader/acpi/Makefile	2013-10-16 11:51:53.000000000 +0800
> >> > +++ hvmloader_new//acpi/Makefile	2013-10-16 11:51:58.000000000 +0800
> >> > @@ -36,18 +36,34 @@
> >> >  
> >> >  dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
> >> >  	awk 'NR > 1 {print s} {s=$$0}' $< > $@
> >> > -	./mk_dsdt --dm-version qemu-xen >> $@
> >> > +	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@
> >> 
> >> This must never be done - if someone hits Ctrl-C in the middle of
> >> this, you'll have a modified but incomplete generated file. You
> >> either need to use properly chained rules, or do all output to a
> >> temporary file which you rename as the last step.
> >> 
> >> I realize that the problem existed before your change, but you
> >> making it worse requires doing it properly now.
> >
> > The correct way to do this is to generate to a temporary file and then
> > use $(call move-if-changed,$@.tmp,$@). There are a bunch of examples in
> > tools/libxl/Makefile and elsewhere.
> 
> Quoting the GNU make manual[*]:
> 
>     So generally the right thing to do is to delete the target file if
>     the recipe fails after beginning to change the file.  make will do
>     this if .DELETE_ON_ERROR appears as a target.  This is almost always
>     what you want make to do, but it is not historical practice; so for
>     compatibility, you must explicitly request it.
> 
> In my opinion, every Makefile should request it.
> 
> [*] https://www.gnu.org/software/make/manual/html_node/Errors.html

I think this is somewhat orthogonal to the use of move-if-changed which
is there to ensure that the timestamp doesn't change gratuitously and
cause a load of knock on rebuilds even though the regenerated content is
identical.

Ian.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
  2013-10-16 10:49     ` Markus Armbruster
  2013-10-16 10:58       ` Ian Campbell
@ 2013-10-16 10:58       ` Ian Campbell
  1 sibling, 0 replies; 38+ messages in thread
From: Ian Campbell @ 2013-10-16 10:58 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Gonglei (Arei),
	Stefano Stabellini, Yanqiangjun, Luonengjun, qemu-devel,
	xen-devel, Fabio Fantoni, Jan Beulich, anthony.perard,
	Hanweidong (Randy), Gaowei (UVP), Huangweidong (Hardware)

On Wed, 2013-10-16 at 12:49 +0200, Markus Armbruster wrote:
> Ian Campbell <Ian.Campbell@citrix.com> writes:
> 
> > On Wed, 2013-10-16 at 10:54 +0100, Jan Beulich wrote:
> >> >>> On 16.10.13 at 08:30, "Gonglei (Arei)" <arei.gonglei@huawei.com> wrote:
> >> > --- hvmloader/acpi/Makefile	2013-10-16 11:51:53.000000000 +0800
> >> > +++ hvmloader_new//acpi/Makefile	2013-10-16 11:51:58.000000000 +0800
> >> > @@ -36,18 +36,34 @@
> >> >  
> >> >  dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
> >> >  	awk 'NR > 1 {print s} {s=$$0}' $< > $@
> >> > -	./mk_dsdt --dm-version qemu-xen >> $@
> >> > +	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@
> >> 
> >> This must never be done - if someone hits Ctrl-C in the middle of
> >> this, you'll have a modified but incomplete generated file. You
> >> either need to use properly chained rules, or do all output to a
> >> temporary file which you rename as the last step.
> >> 
> >> I realize that the problem existed before your change, but you
> >> making it worse requires doing it properly now.
> >
> > The correct way to do this is to generate to a temporary file and then
> > use $(call move-if-changed,$@.tmp,$@). There are a bunch of examples in
> > tools/libxl/Makefile and elsewhere.
> 
> Quoting the GNU make manual[*]:
> 
>     So generally the right thing to do is to delete the target file if
>     the recipe fails after beginning to change the file.  make will do
>     this if .DELETE_ON_ERROR appears as a target.  This is almost always
>     what you want make to do, but it is not historical practice; so for
>     compatibility, you must explicitly request it.
> 
> In my opinion, every Makefile should request it.
> 
> [*] https://www.gnu.org/software/make/manual/html_node/Errors.html

I think this is somewhat orthogonal to the use of move-if-changed which
is there to ensure that the timestamp doesn't change gratuitously and
cause a load of knock on rebuilds even though the regenerated content is
identical.

Ian.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [Xen-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
  2013-10-16 10:58       ` Ian Campbell
@ 2013-10-16 11:10         ` Markus Armbruster
  2013-10-16 12:03           ` Jan Beulich
  2013-10-16 12:03           ` Jan Beulich
  2013-10-16 11:10         ` Markus Armbruster
  1 sibling, 2 replies; 38+ messages in thread
From: Markus Armbruster @ 2013-10-16 11:10 UTC (permalink / raw)
  To: Ian Campbell
  Cc: Gonglei (Arei),
	Stefano Stabellini, Yanqiangjun, Luonengjun, qemu-devel,
	xen-devel, Fabio Fantoni, Jan Beulich, anthony.perard,
	Hanweidong (Randy), Gaowei (UVP), Huangweidong (Hardware)

Ian Campbell <Ian.Campbell@citrix.com> writes:

> On Wed, 2013-10-16 at 12:49 +0200, Markus Armbruster wrote:
>> Ian Campbell <Ian.Campbell@citrix.com> writes:
>> 
>> > On Wed, 2013-10-16 at 10:54 +0100, Jan Beulich wrote:
>> >> >>> On 16.10.13 at 08:30, "Gonglei (Arei)" <arei.gonglei@huawei.com> wrote:
>> >> > --- hvmloader/acpi/Makefile	2013-10-16 11:51:53.000000000 +0800
>> >> > +++ hvmloader_new//acpi/Makefile	2013-10-16 11:51:58.000000000 +0800
>> >> > @@ -36,18 +36,34 @@
>> >> >  
>> >> >  dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
>> >> >  	awk 'NR > 1 {print s} {s=$$0}' $< > $@
>> >> > -	./mk_dsdt --dm-version qemu-xen >> $@
>> >> > +	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@
>> >> 
>> >> This must never be done - if someone hits Ctrl-C in the middle of
>> >> this, you'll have a modified but incomplete generated file. You
>> >> either need to use properly chained rules, or do all output to a
>> >> temporary file which you rename as the last step.
>> >> 
>> >> I realize that the problem existed before your change, but you
>> >> making it worse requires doing it properly now.
>> >
>> > The correct way to do this is to generate to a temporary file and then
>> > use $(call move-if-changed,$@.tmp,$@). There are a bunch of examples in
>> > tools/libxl/Makefile and elsewhere.
>> 
>> Quoting the GNU make manual[*]:
>> 
>>     So generally the right thing to do is to delete the target file if
>>     the recipe fails after beginning to change the file.  make will do
>>     this if .DELETE_ON_ERROR appears as a target.  This is almost always
>>     what you want make to do, but it is not historical practice; so for
>>     compatibility, you must explicitly request it.
>> 
>> In my opinion, every Makefile should request it.
>> 
>> [*] https://www.gnu.org/software/make/manual/html_node/Errors.html
>
> I think this is somewhat orthogonal to the use of move-if-changed which
> is there to ensure that the timestamp doesn't change gratuitously and
> cause a load of knock on rebuilds even though the regenerated content is
> identical.

Yes.  I was latching onto the "if someone hits Ctrl-C in the middle of
this, you'll have a modified but incomplete generated file" phrase.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
  2013-10-16 10:58       ` Ian Campbell
  2013-10-16 11:10         ` Markus Armbruster
@ 2013-10-16 11:10         ` Markus Armbruster
  1 sibling, 0 replies; 38+ messages in thread
From: Markus Armbruster @ 2013-10-16 11:10 UTC (permalink / raw)
  To: Ian Campbell
  Cc: Gonglei (Arei),
	Stefano Stabellini, Yanqiangjun, Luonengjun, qemu-devel,
	xen-devel, Fabio Fantoni, Jan Beulich, anthony.perard,
	Hanweidong (Randy), Gaowei (UVP), Huangweidong (Hardware)

Ian Campbell <Ian.Campbell@citrix.com> writes:

> On Wed, 2013-10-16 at 12:49 +0200, Markus Armbruster wrote:
>> Ian Campbell <Ian.Campbell@citrix.com> writes:
>> 
>> > On Wed, 2013-10-16 at 10:54 +0100, Jan Beulich wrote:
>> >> >>> On 16.10.13 at 08:30, "Gonglei (Arei)" <arei.gonglei@huawei.com> wrote:
>> >> > --- hvmloader/acpi/Makefile	2013-10-16 11:51:53.000000000 +0800
>> >> > +++ hvmloader_new//acpi/Makefile	2013-10-16 11:51:58.000000000 +0800
>> >> > @@ -36,18 +36,34 @@
>> >> >  
>> >> >  dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
>> >> >  	awk 'NR > 1 {print s} {s=$$0}' $< > $@
>> >> > -	./mk_dsdt --dm-version qemu-xen >> $@
>> >> > +	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@
>> >> 
>> >> This must never be done - if someone hits Ctrl-C in the middle of
>> >> this, you'll have a modified but incomplete generated file. You
>> >> either need to use properly chained rules, or do all output to a
>> >> temporary file which you rename as the last step.
>> >> 
>> >> I realize that the problem existed before your change, but you
>> >> making it worse requires doing it properly now.
>> >
>> > The correct way to do this is to generate to a temporary file and then
>> > use $(call move-if-changed,$@.tmp,$@). There are a bunch of examples in
>> > tools/libxl/Makefile and elsewhere.
>> 
>> Quoting the GNU make manual[*]:
>> 
>>     So generally the right thing to do is to delete the target file if
>>     the recipe fails after beginning to change the file.  make will do
>>     this if .DELETE_ON_ERROR appears as a target.  This is almost always
>>     what you want make to do, but it is not historical practice; so for
>>     compatibility, you must explicitly request it.
>> 
>> In my opinion, every Makefile should request it.
>> 
>> [*] https://www.gnu.org/software/make/manual/html_node/Errors.html
>
> I think this is somewhat orthogonal to the use of move-if-changed which
> is there to ensure that the timestamp doesn't change gratuitously and
> cause a load of knock on rebuilds even though the regenerated content is
> identical.

Yes.  I was latching onto the "if someone hits Ctrl-C in the middle of
this, you'll have a modified but incomplete generated file" phrase.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [Xen-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
  2013-10-16 11:10         ` Markus Armbruster
@ 2013-10-16 12:03           ` Jan Beulich
  2013-10-22  4:08             ` Gonglei (Arei)
  2013-10-22  4:08             ` [Qemu-devel] " Gonglei (Arei)
  2013-10-16 12:03           ` Jan Beulich
  1 sibling, 2 replies; 38+ messages in thread
From: Jan Beulich @ 2013-10-16 12:03 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Yanqiangjun, Ian Campbell, Hanweidong (Randy),
	Stefano Stabellini, Luonengjun, qemu-devel, xen-devel,
	Fabio Fantoni, Gonglei (Arei), anthony.perard, Gaowei (UVP),
	Huangweidong (Hardware)

>>> On 16.10.13 at 13:10, Markus Armbruster <armbru@redhat.com> wrote:
> Ian Campbell <Ian.Campbell@citrix.com> writes:
> 
>> On Wed, 2013-10-16 at 12:49 +0200, Markus Armbruster wrote:
>>> Ian Campbell <Ian.Campbell@citrix.com> writes:
>>> 
>>> > On Wed, 2013-10-16 at 10:54 +0100, Jan Beulich wrote:
>>> >> >>> On 16.10.13 at 08:30, "Gonglei (Arei)" <arei.gonglei@huawei.com> wrote:
>>> >> > --- hvmloader/acpi/Makefile	2013-10-16 11:51:53.000000000 +0800
>>> >> > +++ hvmloader_new//acpi/Makefile	2013-10-16 11:51:58.000000000 +0800
>>> >> > @@ -36,18 +36,34 @@
>>> >> >  
>>> >> >  dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
>>> >> >  	awk 'NR > 1 {print s} {s=$$0}' $< > $@
>>> >> > -	./mk_dsdt --dm-version qemu-xen >> $@
>>> >> > +	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@
>>> >> 
>>> >> This must never be done - if someone hits Ctrl-C in the middle of
>>> >> this, you'll have a modified but incomplete generated file. You
>>> >> either need to use properly chained rules, or do all output to a
>>> >> temporary file which you rename as the last step.
>>> >> 
>>> >> I realize that the problem existed before your change, but you
>>> >> making it worse requires doing it properly now.
>>> >
>>> > The correct way to do this is to generate to a temporary file and then
>>> > use $(call move-if-changed,$@.tmp,$@). There are a bunch of examples in
>>> > tools/libxl/Makefile and elsewhere.
>>> 
>>> Quoting the GNU make manual[*]:
>>> 
>>>     So generally the right thing to do is to delete the target file if
>>>     the recipe fails after beginning to change the file.  make will do
>>>     this if .DELETE_ON_ERROR appears as a target.  This is almost always
>>>     what you want make to do, but it is not historical practice; so for
>>>     compatibility, you must explicitly request it.
>>> 
>>> In my opinion, every Makefile should request it.
>>> 
>>> [*] https://www.gnu.org/software/make/manual/html_node/Errors.html 
>>
>> I think this is somewhat orthogonal to the use of move-if-changed which
>> is there to ensure that the timestamp doesn't change gratuitously and
>> cause a load of knock on rebuilds even though the regenerated content is
>> identical.
> 
> Yes.  I was latching onto the "if someone hits Ctrl-C in the middle of
> this, you'll have a modified but incomplete generated file" phrase.

Right, but Ctrl-C is only the soft way of failing. If the system
happens to crash at the right moment, make won't be able to go
and delete the file anymore. IOW the move-if-changed approach
covers a wider range of situations _and_ had the benefit of
avoiding unnecessary rebuilds.

Jan

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
  2013-10-16 11:10         ` Markus Armbruster
  2013-10-16 12:03           ` Jan Beulich
@ 2013-10-16 12:03           ` Jan Beulich
  1 sibling, 0 replies; 38+ messages in thread
From: Jan Beulich @ 2013-10-16 12:03 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Yanqiangjun, Ian Campbell, Hanweidong (Randy),
	Stefano Stabellini, Luonengjun, qemu-devel, xen-devel,
	Fabio Fantoni, Gonglei (Arei), anthony.perard, Gaowei (UVP),
	Huangweidong (Hardware)

>>> On 16.10.13 at 13:10, Markus Armbruster <armbru@redhat.com> wrote:
> Ian Campbell <Ian.Campbell@citrix.com> writes:
> 
>> On Wed, 2013-10-16 at 12:49 +0200, Markus Armbruster wrote:
>>> Ian Campbell <Ian.Campbell@citrix.com> writes:
>>> 
>>> > On Wed, 2013-10-16 at 10:54 +0100, Jan Beulich wrote:
>>> >> >>> On 16.10.13 at 08:30, "Gonglei (Arei)" <arei.gonglei@huawei.com> wrote:
>>> >> > --- hvmloader/acpi/Makefile	2013-10-16 11:51:53.000000000 +0800
>>> >> > +++ hvmloader_new//acpi/Makefile	2013-10-16 11:51:58.000000000 +0800
>>> >> > @@ -36,18 +36,34 @@
>>> >> >  
>>> >> >  dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
>>> >> >  	awk 'NR > 1 {print s} {s=$$0}' $< > $@
>>> >> > -	./mk_dsdt --dm-version qemu-xen >> $@
>>> >> > +	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@
>>> >> 
>>> >> This must never be done - if someone hits Ctrl-C in the middle of
>>> >> this, you'll have a modified but incomplete generated file. You
>>> >> either need to use properly chained rules, or do all output to a
>>> >> temporary file which you rename as the last step.
>>> >> 
>>> >> I realize that the problem existed before your change, but you
>>> >> making it worse requires doing it properly now.
>>> >
>>> > The correct way to do this is to generate to a temporary file and then
>>> > use $(call move-if-changed,$@.tmp,$@). There are a bunch of examples in
>>> > tools/libxl/Makefile and elsewhere.
>>> 
>>> Quoting the GNU make manual[*]:
>>> 
>>>     So generally the right thing to do is to delete the target file if
>>>     the recipe fails after beginning to change the file.  make will do
>>>     this if .DELETE_ON_ERROR appears as a target.  This is almost always
>>>     what you want make to do, but it is not historical practice; so for
>>>     compatibility, you must explicitly request it.
>>> 
>>> In my opinion, every Makefile should request it.
>>> 
>>> [*] https://www.gnu.org/software/make/manual/html_node/Errors.html 
>>
>> I think this is somewhat orthogonal to the use of move-if-changed which
>> is there to ensure that the timestamp doesn't change gratuitously and
>> cause a load of knock on rebuilds even though the regenerated content is
>> identical.
> 
> Yes.  I was latching onto the "if someone hits Ctrl-C in the middle of
> this, you'll have a modified but incomplete generated file" phrase.

Right, but Ctrl-C is only the soft way of failing. If the system
happens to crash at the right moment, make won't be able to go
and delete the file anymore. IOW the move-if-changed approach
covers a wider range of situations _and_ had the benefit of
avoiding unnecessary rebuilds.

Jan

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [Xen-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
  2013-10-16 12:03           ` Jan Beulich
@ 2013-10-22  4:08             ` Gonglei (Arei)
  2013-10-22  8:06               ` [Qemu-devel] " Jan Beulich
  2013-10-22  8:06               ` [Qemu-devel] [Xen-devel] " Jan Beulich
  2013-10-22  4:08             ` [Qemu-devel] " Gonglei (Arei)
  1 sibling, 2 replies; 38+ messages in thread
From: Gonglei (Arei) @ 2013-10-22  4:08 UTC (permalink / raw)
  To: Jan Beulich, Markus Armbruster
  Cc: Yanqiangjun, Ian Campbell, Hanweidong (Randy),
	Stefano Stabellini, Luonengjun, qemu-devel, xen-devel,
	Fabio Fantoni, anthony.perard, Gaowei (UVP),
	Huangweidong (Hardware)

[-- Attachment #1: Type: text/plain, Size: 28259 bytes --]

Hi, guys. The new patch has been modified based on the principles you suggested, thank you so much.
Last time I test the patch based on the codes of 4.3.0.
This time, I found that the system based on the codes of trunk causes the VM reboot again and again, which I have not found out the reason.
So i can not test the patch based on the codes of trunk (details in EJ0_ACPI_PCI_Hotplug.patch)..
The new patch works well based on the codes of 4.3.0 (details in 4.3.0.patch).

 In Xen platform, after using upstream qemu, the all of pci devices will show hotplug in the windows guest.
 In this situation, the windows guest may occur blue screen when VM' user click the icon of VGA card for trying unplug VGA card.
 However, we don't hope VM's user can do such dangerous operation, and showing all pci devices inside the guest OS is unfriendly.
 This is done by runtime patching:
  - Rename _EJ0 methods for PCI slots in DSDT to EJ0_:note that this has the same checksum, but is ignored by OSPM.
  - At compile time, look for these methods in ASL source, find the matching AML, and store the offsets of these methods in a table named aml_ej0_data.
  - At run time, go over aml_ej0_data, check which slots not support hotplug and patch the ACPI table, replacing _EJ0 with EJ0_.

Signed-off-by: gaowei <gao.gaowei@huawei.com>
Signed-off-by: gonglei <arei.gonglei@huawei.com>
---
 tools/firmware/hvmloader/acpi/Makefile             |  46 ++-
 tools/firmware/hvmloader/acpi/acpi2_0.h            |   5 +
 tools/firmware/hvmloader/acpi/build.c              |  24 +-
 tools/firmware/hvmloader/acpi/dsdt.asl             |   1 +
 tools/firmware/hvmloader/acpi/mk_dsdt.c            |   2 +
 tools/firmware/hvmloader/mkhex                     |   0
 tools/firmware/hvmloader/ovmf.c                    |   6 +-
 tools/firmware/hvmloader/rombios.c                 |   4 +
 tools/firmware/hvmloader/seabios.c                 |   8 +
 tools/firmware/hvmloader/tools/acpi_extract.py     | 308 +++++++++++++++++++++
 .../hvmloader/tools/acpi_extract_preprocess.py     |  41 +++
 11 files changed, 431 insertions(+), 14 deletions(-)
 mode change 100755 => 100644 tools/firmware/hvmloader/mkhex
 create mode 100644 tools/firmware/hvmloader/tools/acpi_extract.py
 create mode 100644 tools/firmware/hvmloader/tools/acpi_extract_preprocess.py

diff --git a/tools/firmware/hvmloader/acpi/Makefile b/tools/firmware/hvmloader/acpi/Makefile
index 2c50851..8b3f7ac 100644
--- a/tools/firmware/hvmloader/acpi/Makefile
+++ b/tools/firmware/hvmloader/acpi/Makefile
@@ -24,30 +24,46 @@ OBJS  = $(patsubst %.c,%.o,$(C_SRC))
 CFLAGS += $(CFLAGS_xeninclude)
 
 vpath iasl $(PATH)
+vpath python $(PATH)
+
+.DELETE_ON_ERROR:$(filter dsdt_%.c,$(C_SRC))
+
 all: acpi.a
 
 ssdt_s3.h ssdt_s4.h ssdt_pm.h ssdt_tpm.h: %.h: %.asl iasl
 	iasl -vs -p $* -tc $<
-	sed -e 's/AmlCode/$*/g' $*.hex >$@
+	sed -e 's/AmlCode/$*/g' $*.hex >$@.tmp
+	$(call move-if-changed,$@.tmp $@)
 	rm -f $*.hex $*.aml
 
 mk_dsdt: mk_dsdt.c
 	$(HOSTCC) $(HOSTCFLAGS) $(CFLAGS_xeninclude) -o $@ mk_dsdt.c
 
 dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
-	awk 'NR > 1 {print s} {s=$$0}' $< > $@
-	./mk_dsdt --dm-version qemu-xen >> $@
-
+	awk 'NR > 1 {print s} {s=$$0}' $< > $@.tmp
+	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@.tmp
+	./mk_dsdt --dm-version qemu-xen >> $@.tmp
+	sed -i 's/aml_ej0_name/dsdt_anycpu_qemu_xen_aml_ej0_name/g' $@.tmp
+	sed -i 's/aml_adr_dword/dsdt_anycpu_qemu_xen_aml_adr_dword/g' $@.tmp
+	$(call move-if-changed,$@.tmp $@)
+	
 # NB. awk invocation is a portable alternative to 'head -n -1'
 dsdt_%cpu.asl: dsdt.asl mk_dsdt
-	awk 'NR > 1 {print s} {s=$$0}' $< > $@
-	./mk_dsdt --maxcpu $*  >> $@
+	awk 'NR > 1 {print s} {s=$$0}' $< > $@.tmp
+	sed -i 's/AmlCode/dsdt_$*cpu/g' $@.tmp
+	./mk_dsdt --maxcpu $*  >> $@.tmp
+	$(call move-if-changed,$@.tmp $@)
 
-$(filter dsdt_%.c,$(C_SRC)): %.c: iasl %.asl
-	iasl -vs -p $* -tc $*.asl
-	sed -e 's/AmlCode/$*/g' $*.hex >$@
-	echo "int $*_len=sizeof($*);" >>$@
-	rm -f $*.aml $*.hex
+$(filter dsdt_%.c,$(C_SRC)): %.c: iasl python %.asl
+	cpp -P $*.asl > $*.asl.i.orig
+	python ../tools/acpi_extract_preprocess.py $*.asl.i.orig > $*.asl.i
+	iasl -vs -l -tc -p $* $*.asl.i
+	python ../tools/acpi_extract.py $*.lst > $@.tmp
+	echo "int $*_len=sizeof($*);" >>$@.tmp
+	if grep -q "$*_aml_ej0_name" $@.tmp; then echo "int $*_aml_ej0_name_len=sizeof($*_aml_ej0_name);" >>$@.tmp; fi
+	if grep -q "$*_aml_adr_dword" $@.tmp; then echo "int $*_aml_adr_dword_len=sizeof($*_aml_adr_dword);" >>$@.tmp;fi
+	$(call move-if-changed,$@.tmp $@)
+	rm -f $*.aml $*.hex $*.asl.i.orig $*.asl.i $*.lst
 
 iasl:
 	@echo
@@ -57,6 +73,12 @@ iasl:
 	@echo 
 	@exit 1
 
+python:
+	@echo
+	@echo "python is needed"
+	@echo
+	@exit 1
+
 build.o: ssdt_s3.h ssdt_s4.h ssdt_pm.h ssdt_tpm.h
 
 acpi.a: $(OBJS)
@@ -64,7 +86,7 @@ acpi.a: $(OBJS)
 
 clean:
 	rm -rf *.a *.o $(IASL_VER) $(IASL_VER).tar.gz $(DEPS)
-	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl
+	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl *.asl.i *.asl.i.orig *.lst *.tmp
 
 install: all
 
diff --git a/tools/firmware/hvmloader/acpi/acpi2_0.h b/tools/firmware/hvmloader/acpi/acpi2_0.h
index 7b22d80..d0c83b8 100644
--- a/tools/firmware/hvmloader/acpi/acpi2_0.h
+++ b/tools/firmware/hvmloader/acpi/acpi2_0.h
@@ -396,6 +396,11 @@ struct acpi_config {
     int dsdt_anycpu_len;
     unsigned char *dsdt_15cpu;
     int dsdt_15cpu_len;
+    unsigned short *aml_ej0_name;
+    unsigned short *aml_adr_dword;
+    int aml_ej0_name_len;
+    int aml_adr_dword_len;
+    
 };
 
 void acpi_build_tables(struct acpi_config *config, unsigned int physical);
diff --git a/tools/firmware/hvmloader/acpi/build.c b/tools/firmware/hvmloader/acpi/build.c
index f1dd3f0..35681aa 100644
--- a/tools/firmware/hvmloader/acpi/build.c
+++ b/tools/firmware/hvmloader/acpi/build.c
@@ -30,6 +30,9 @@
 #define align16(sz)        (((sz) + 15) & ~15)
 #define fixed_strcpy(d, s) strncpy((d), (s), sizeof(d))
 
+
+#define PCI_RMV_BASE 0xae0c
+
 extern struct acpi_20_rsdp Rsdp;
 extern struct acpi_20_rsdt Rsdt;
 extern struct acpi_20_xsdt Xsdt;
@@ -404,6 +407,7 @@ void acpi_build_tables(struct acpi_config *config, unsigned int physical)
     unsigned char       *dsdt;
     unsigned long        secondary_tables[ACPI_MAX_SECONDARY_TABLES];
     int                  nr_secondaries, i;
+    unsigned int rmvc_pcrm = 0;
 
     /* Allocate and initialise the acpi info area. */
     mem_hole_populate_ram(ACPI_INFO_PHYSICAL_ADDRESS >> PAGE_SHIFT, 1);
@@ -438,9 +442,27 @@ void acpi_build_tables(struct acpi_config *config, unsigned int physical)
         dsdt = mem_alloc(config->dsdt_anycpu_len, 16);
         if (!dsdt) goto oom;
         memcpy(dsdt, config->dsdt_anycpu, config->dsdt_anycpu_len);
-        nr_processor_objects = HVM_MAX_VCPUS;
+        if(config->aml_adr_dword_len && config->aml_ej0_name_len &&
+            (config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]) == config->aml_ej0_name_len/sizeof(config->aml_ej0_name[0])))
+        {
+            rmvc_pcrm = inl(PCI_RMV_BASE); 
+            printf("rmvc_pcrm is %x\n", rmvc_pcrm);
+            for(i = 0;  i < config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]); i ++)
+            {
+                /* Slot is in byte 2 in _ADR */
+                unsigned char slot = dsdt[config->aml_adr_dword[i] + 2] & 0x1F;
+                /* Sanity check */
+                if (memcmp(dsdt + config->aml_ej0_name[i], "_EJ0", 4)) {
+                    goto oom;
+                }
+                if (!(rmvc_pcrm & (0x1 << slot))) {
+                    memcpy(dsdt + config->aml_ej0_name[i], "EJ0_", 4);
+                }
+            }
+        }
     }
 
+    nr_processor_objects = HVM_MAX_VCPUS;
     /*
      * N.B. ACPI 1.0 operating systems may not handle FADT with revision 2
      * or above properly, notably Windows 2000, which tries to copy FADT
diff --git a/tools/firmware/hvmloader/acpi/dsdt.asl b/tools/firmware/hvmloader/acpi/dsdt.asl
index 247a8ad..1e7695b 100644
--- a/tools/firmware/hvmloader/acpi/dsdt.asl
+++ b/tools/firmware/hvmloader/acpi/dsdt.asl
@@ -16,6 +16,7 @@
  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  * Place - Suite 330, Boston, MA 02111-1307 USA.
  */
+ACPI_EXTRACT_ALL_CODE AmlCode
 
 DefinitionBlock ("DSDT.aml", "DSDT", 2, "Xen", "HVM", 0)
 {
diff --git a/tools/firmware/hvmloader/acpi/mk_dsdt.c b/tools/firmware/hvmloader/acpi/mk_dsdt.c
index 996f30b..4180801 100644
--- a/tools/firmware/hvmloader/acpi/mk_dsdt.c
+++ b/tools/firmware/hvmloader/acpi/mk_dsdt.c
@@ -368,7 +368,9 @@ int main(int argc, char **argv)
         /* hotplug_slot */
         for (slot = 1; slot <= 31; slot++) {
             push_block("Device", "S%i", slot); {
+                printf("ACPI_EXTRACT_NAME_DWORD_CONST aml_adr_dword\n");
                 stmt("Name", "_ADR, %#06x0000", slot);
+                printf("ACPI_EXTRACT_METHOD_STRING aml_ej0_name\n");
                 push_block("Method", "_EJ0,1"); {
                     stmt("Store", "ShiftLeft(1, %#06x), B0EJ", slot);
                     stmt("Return", "0x0");
diff --git a/tools/firmware/hvmloader/mkhex b/tools/firmware/hvmloader/mkhex
old mode 100755
new mode 100644
diff --git a/tools/firmware/hvmloader/ovmf.c b/tools/firmware/hvmloader/ovmf.c
index ee4cbbf..27ff0b5 100644
--- a/tools/firmware/hvmloader/ovmf.c
+++ b/tools/firmware/hvmloader/ovmf.c
@@ -79,7 +79,11 @@ static void ovmf_acpi_build_tables(void)
         .dsdt_anycpu = dsdt_anycpu,
         .dsdt_anycpu_len = dsdt_anycpu_len,
         .dsdt_15cpu = NULL, 
-        .dsdt_15cpu_len = 0
+        .dsdt_15cpu_len = 0,
+        .aml_ej0_name = NULL,
+        .aml_adr_dword = NULL,
+        .aml_ej0_name_len = 0,
+        .aml_adr_dword_len = 0,
     };
 
     acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
diff --git a/tools/firmware/hvmloader/rombios.c b/tools/firmware/hvmloader/rombios.c
index 810bd24..803c9fa 100644
--- a/tools/firmware/hvmloader/rombios.c
+++ b/tools/firmware/hvmloader/rombios.c
@@ -179,6 +179,10 @@ static void rombios_acpi_build_tables(void)
         .dsdt_anycpu_len = dsdt_anycpu_len,
         .dsdt_15cpu = dsdt_15cpu,
         .dsdt_15cpu_len = dsdt_15cpu_len,
+        .aml_ej0_name = NULL,
+        .aml_adr_dword = NULL,
+        .aml_ej0_name_len = 0,
+        .aml_adr_dword_len = 0,
     };
 
     acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
diff --git a/tools/firmware/hvmloader/seabios.c b/tools/firmware/hvmloader/seabios.c
index dd7dfbe..ca01d27 100644
--- a/tools/firmware/hvmloader/seabios.c
+++ b/tools/firmware/hvmloader/seabios.c
@@ -33,6 +33,10 @@
 
 extern unsigned char dsdt_anycpu_qemu_xen[];
 extern int dsdt_anycpu_qemu_xen_len;
+extern unsigned short dsdt_anycpu_qemu_xen_aml_ej0_name[];
+extern unsigned short dsdt_anycpu_qemu_xen_aml_adr_dword[];
+extern int dsdt_anycpu_qemu_xen_aml_ej0_name_len;
+extern int dsdt_anycpu_qemu_xen_aml_adr_dword_len;
 
 struct seabios_info {
     char signature[14]; /* XenHVMSeaBIOS\0 */
@@ -99,6 +103,10 @@ static void seabios_acpi_build_tables(void)
         .dsdt_anycpu_len = dsdt_anycpu_qemu_xen_len,
         .dsdt_15cpu = NULL,
         .dsdt_15cpu_len = 0,
+        .aml_ej0_name = dsdt_anycpu_qemu_xen_aml_ej0_name,
+        .aml_adr_dword = dsdt_anycpu_qemu_xen_aml_adr_dword,
+        .aml_ej0_name_len = dsdt_anycpu_qemu_xen_aml_ej0_name_len,
+        .aml_adr_dword_len = dsdt_anycpu_qemu_xen_aml_adr_dword_len,
     };
 
     acpi_build_tables(&config, rsdp);
diff --git a/tools/firmware/hvmloader/tools/acpi_extract.py b/tools/firmware/hvmloader/tools/acpi_extract.py
new file mode 100644
index 0000000..4fa51f7
--- /dev/null
+++ b/tools/firmware/hvmloader/tools/acpi_extract.py
@@ -0,0 +1,308 @@
+#!/usr/bin/python
+# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+# Process mixed ASL/AML listing (.lst file) produced by iasl -l
+# Locate and execute ACPI_EXTRACT directives, output offset info
+# 
+# Documentation of ACPI_EXTRACT_* directive tags:
+# 
+# These directive tags output offset information from AML for BIOS runtime
+# table generation.
+# Each directive is of the form:
+# ACPI_EXTRACT_<TYPE> <array_name> <Operator> (...)
+# and causes the extractor to create an array
+# named <array_name> with offset, in the generated AML,
+# of an object of a given type in the following <Operator>.
+# 
+# A directive must fit on a single code line.
+# 
+# Object type in AML is verified, a mismatch causes a build failure.
+# 
+# Directives and operators currently supported are:
+# ACPI_EXTRACT_NAME_DWORD_CONST - extract a Dword Const object from Name()
+# ACPI_EXTRACT_NAME_WORD_CONST - extract a Word Const object from Name()
+# ACPI_EXTRACT_NAME_BYTE_CONST - extract a Byte Const object from Name()
+# ACPI_EXTRACT_METHOD_STRING - extract a NameString from Method()
+# ACPI_EXTRACT_NAME_STRING - extract a NameString from Name()
+# ACPI_EXTRACT_PROCESSOR_START - start of Processor() block
+# ACPI_EXTRACT_PROCESSOR_STRING - extract a NameString from Processor()
+# ACPI_EXTRACT_PROCESSOR_END - offset at last byte of Processor() + 1
+# ACPI_EXTRACT_PKG_START - start of Package block
+#
+# ACPI_EXTRACT_ALL_CODE - create an array storing the generated AML bytecode
+# 
+# ACPI_EXTRACT is not allowed anywhere else in code, except in comments.
+
+import re;
+import sys;
+import fileinput;
+
+aml = []
+asl = []
+output = {}
+debug = ""
+
+class asl_line:
+    line = None
+    lineno = None
+    aml_offset = None
+
+def die(diag):
+    sys.stderr.write("Error: %s; %s\n" % (diag, debug))
+    sys.exit(1)
+    
+#Store an ASL command, matching AML offset, and input line (for debugging)
+def add_asl(lineno, line):
+    l = asl_line()
+    l.line = line
+    l.lineno = lineno
+    l.aml_offset = len(aml)
+    asl.append(l)
+
+#Store an AML byte sequence
+#Verify that offset output by iasl matches # of bytes so far
+def add_aml(offset, line):
+    o = int(offset, 16);
+    # Sanity check: offset must match size of code so far
+    if (o != len(aml)):
+        die("Offset 0x%x != 0x%x" % (o, len(aml)))
+    # Strip any trailing dots and ASCII dump after "
+    line = re.sub(r'\s*\.*\s*".*$',"", line)
+    # Strip traling whitespace
+    line = re.sub(r'\s+$',"", line)
+    # Strip leading whitespace
+    line = re.sub(r'^\s+',"", line)
+    # Split on whitespace
+    code = re.split(r'\s+', line)
+    for c in code:
+        # Require a legal hex number, two digits
+        if (not(re.search(r'^[0-9A-Fa-f][0-9A-Fa-f]$', c))):
+            die("Unexpected octet %s" % c);
+        aml.append(int(c, 16));
+
+# Process aml bytecode array, decoding AML
+def aml_pkglen_bytes(offset):
+    # PkgLength can be multibyte. Bits 8-7 give the # of extra bytes.
+    pkglenbytes = aml[offset] >> 6;
+    return pkglenbytes + 1
+
+def aml_pkglen(offset):
+    pkgstart = offset
+    pkglenbytes = aml_pkglen_bytes(offset)
+    pkglen = aml[offset] & 0x3F
+    # If multibyte, first nibble only uses bits 0-3
+    if ((pkglenbytes > 0) and (pkglen & 0x30)):
+        die("PkgLen bytes 0x%x but first nibble 0x%x expected 0x0X" %
+            (pkglen, pkglen))
+    offset += 1
+    pkglenbytes -= 1
+    for i in range(pkglenbytes):
+        pkglen |= aml[offset + i] << (i * 8 + 4)
+    if (len(aml) < pkgstart + pkglen):
+        die("PckgLen 0x%x at offset 0x%x exceeds AML size 0x%x" %
+            (pkglen, offset, len(aml)))
+    return pkglen
+
+# Given method offset, find its NameString offset
+def aml_method_string(offset):
+    #0x14 MethodOp PkgLength NameString MethodFlags TermList
+    if (aml[offset] != 0x14):
+        die( "Method offset 0x%x: expected 0x14 actual 0x%x" %
+             (offset, aml[offset]));
+    offset += 1;
+    pkglenbytes = aml_pkglen_bytes(offset)
+    offset += pkglenbytes;
+    return offset;
+
+# Given name offset, find its NameString offset
+def aml_name_string(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x08):
+        die( "Name offset 0x%x: expected 0x08 actual 0x%x" %
+             (offset, aml[offset]));
+    offset += 1
+    # Block Name Modifier. Skip it.
+    if (aml[offset] == 0x5c or aml[offset] == 0x5e):
+        offset += 1
+    return offset;
+
+# Given data offset, find dword const offset
+def aml_data_dword_const(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x0C):
+        die( "Name offset 0x%x: expected 0x0C actual 0x%x" %
+             (offset, aml[offset]));
+    return offset + 1;
+
+# Given data offset, find word const offset
+def aml_data_word_const(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x0B):
+        die( "Name offset 0x%x: expected 0x0B actual 0x%x" %
+             (offset, aml[offset]));
+    return offset + 1;
+
+# Given data offset, find byte const offset
+def aml_data_byte_const(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x0A):
+        die( "Name offset 0x%x: expected 0x0A actual 0x%x" %
+             (offset, aml[offset]));
+    return offset + 1;
+
+# Given name offset, find dword const offset
+def aml_name_dword_const(offset):
+    return aml_data_dword_const(aml_name_string(offset) + 4)
+
+# Given name offset, find word const offset
+def aml_name_word_const(offset):
+    return aml_data_word_const(aml_name_string(offset) + 4)
+
+# Given name offset, find byte const offset
+def aml_name_byte_const(offset):
+    return aml_data_byte_const(aml_name_string(offset) + 4)
+
+def aml_processor_start(offset):
+    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
+    if ((aml[offset] != 0x5B) or (aml[offset + 1] != 0x83)):
+        die( "Name offset 0x%x: expected 0x5B 0x83 actual 0x%x 0x%x" %
+             (offset, aml[offset], aml[offset + 1]));
+    return offset
+
+def aml_processor_string(offset):
+    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
+    start = aml_processor_start(offset)
+    offset += 2
+    pkglenbytes = aml_pkglen_bytes(offset)
+    offset += pkglenbytes
+    return offset
+
+def aml_processor_end(offset):
+    start = aml_processor_start(offset)
+    offset += 2
+    pkglenbytes = aml_pkglen_bytes(offset)
+    pkglen = aml_pkglen(offset)
+    return offset + pkglen
+
+def aml_package_start(offset):
+    offset = aml_name_string(offset) + 4
+    # 0x12 PkgLength NumElements PackageElementList
+    if (aml[offset] != 0x12):
+        die( "Name offset 0x%x: expected 0x12 actual 0x%x" %
+             (offset, aml[offset]));
+    offset += 1
+    return offset + aml_pkglen_bytes(offset) + 1
+
+lineno = 0
+for line in fileinput.input():
+    # Strip trailing newline
+    line = line.rstrip();
+    # line number and debug string to output in case of errors
+    lineno = lineno + 1
+    debug = "input line %d: %s" % (lineno, line)
+    #ASL listing: space, then line#, then ...., then code
+    pasl = re.compile('^\s+([0-9]+)\.\.\.\.\s*')
+    m = pasl.search(line)
+    if (m):
+        add_asl(lineno, pasl.sub("", line));
+    # AML listing: offset in hex, then ...., then code
+    paml = re.compile('^([0-9A-Fa-f]+)\.\.\.\.\s*')
+    m = paml.search(line)
+    if (m):
+        add_aml(m.group(1), paml.sub("", line))
+
+# Now go over code
+# Track AML offset of a previous non-empty ASL command
+prev_aml_offset = -1
+for i in range(len(asl)):
+    debug = "input line %d: %s" % (asl[i].lineno, asl[i].line)
+
+    l = asl[i].line
+
+    # skip if not an extract directive
+    a = len(re.findall(r'ACPI_EXTRACT', l))
+    if (not a):
+        # If not empty, store AML offset. Will be used for sanity checks
+        # IASL seems to put {}. at random places in the listing.
+        # Ignore any non-words for the purpose of this test.
+        m = re.search(r'\w+', l)
+        if (m):
+                prev_aml_offset = asl[i].aml_offset
+        continue
+
+    if (a > 1):
+        die("Expected at most one ACPI_EXTRACT per line, actual %d" % a)
+
+    mext = re.search(r'''
+                      ^\s* # leading whitespace
+                      /\*\s* # start C comment
+                      (ACPI_EXTRACT_\w+) # directive: group(1)
+                      \s+ # whitspace separates directive from array name
+                      (\w+) # array name: group(2)
+                      \s*\*/ # end of C comment
+                      \s*$ # trailing whitespace
+                      ''', l, re.VERBOSE)
+    if (not mext):
+        die("Stray ACPI_EXTRACT in input")
+
+    # previous command must have produced some AML,
+    # otherwise we are in a middle of a block
+    if (prev_aml_offset == asl[i].aml_offset):
+        die("ACPI_EXTRACT directive in the middle of a block")
+
+    directive = mext.group(1)
+    array = mext.group(2)
+    offset = asl[i].aml_offset
+
+    if (directive == "ACPI_EXTRACT_ALL_CODE"):
+        if array in output:
+            die("%s directive used more than once" % directive)
+        output[array] = aml
+        continue
+    if (directive == "ACPI_EXTRACT_NAME_DWORD_CONST"):
+        offset = aml_name_dword_const(offset)
+    elif (directive == "ACPI_EXTRACT_NAME_WORD_CONST"):
+        offset = aml_name_word_const(offset)
+    elif (directive == "ACPI_EXTRACT_NAME_BYTE_CONST"):
+        offset = aml_name_byte_const(offset)
+    elif (directive == "ACPI_EXTRACT_NAME_STRING"):
+        offset = aml_name_string(offset)
+    elif (directive == "ACPI_EXTRACT_METHOD_STRING"):
+        offset = aml_method_string(offset)
+    elif (directive == "ACPI_EXTRACT_PROCESSOR_START"):
+        offset = aml_processor_start(offset)
+    elif (directive == "ACPI_EXTRACT_PROCESSOR_STRING"):
+        offset = aml_processor_string(offset)
+    elif (directive == "ACPI_EXTRACT_PROCESSOR_END"):
+        offset = aml_processor_end(offset)
+    elif (directive == "ACPI_EXTRACT_PKG_START"):
+        offset = aml_package_start(offset)
+    else:
+        die("Unsupported directive %s" % directive)
+
+    if array not in output:
+        output[array] = []
+    output[array].append(offset)
+
+debug = "at end of file"
+
+def get_value_type(maxvalue):
+    #Use type large enough to fit the table
+    if (maxvalue >= 0x10000):
+            return "int"
+    elif (maxvalue >= 0x100):
+            return "short"
+    else:
+            return "char"
+
+# Pretty print output
+for array in output.keys():
+    otype = get_value_type(max(output[array]))
+    odata = []
+    for value in output[array]:
+        odata.append("0x%x" % value)
+    sys.stdout.write("unsigned %s %s[] = {\n" % (otype, array))
+    sys.stdout.write(",\n".join(odata))
+    sys.stdout.write('\n};\n');
diff --git a/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py b/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py
new file mode 100644
index 0000000..4ae364e
--- /dev/null
+++ b/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py
@@ -0,0 +1,41 @@
+#!/usr/bin/python
+# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+# Read a preprocessed ASL listing and put each ACPI_EXTRACT
+# directive in a comment, to make iasl skip it.
+# We also put each directive on a new line, the machinery
+# in tools/acpi_extract.py requires this.
+
+import re;
+import sys;
+import fileinput;
+
+def die(diag):
+    sys.stderr.write("Error: %s\n" % (diag))
+    sys.exit(1)
+
+# Note: () around pattern make split return matched string as part of list
+psplit = re.compile(r''' (
+                          \b # At word boundary
+                          ACPI_EXTRACT_\w+ # directive
+                          \s+ # some whitespace
+                          \w+ # array name
+                         )''', re.VERBOSE);
+
+lineno = 0
+for line in fileinput.input():
+    # line number and debug string to output in case of errors
+    lineno = lineno + 1
+    debug = "input line %d: %s" % (lineno, line.rstrip())
+
+    s = psplit.split(line);
+    # The way split works, each odd item is the matching ACPI_EXTRACT directive.
+    # Put each in a comment, and on a line by itself.
+    for i in range(len(s)):
+        if (i % 2):
+            sys.stdout.write("\n/* %s */\n" % s[i])
+        else:
+            sys.stdout.write(s[i])
+
-- 
1.8.3.4

Best regards,
-Gonglei

> -----Original Message-----
> From: Jan Beulich [mailto:JBeulich@suse.com]
> Sent: Wednesday, October 16, 2013 8:04 PM
> To: Markus Armbruster
> Cc: anthony.perard@citrix.com; Ian Campbell; Stefano Stabellini; Gonglei (Arei);
> Gaowei (UVP); Hanweidong (Randy); Huangweidong (Hardware); Luonengjun;
> Yanqiangjun; xen-devel@lists.xen.org; Fabio Fantoni; qemu-devel@nongnu.org
> Subject: Re: [Qemu-devel] [Xen-devel] Hvmloader: Modify ACPI to only supply
> _EJ0 methods for PCIslots that support hotplug by runtime patching
> 
> >>> On 16.10.13 at 13:10, Markus Armbruster <armbru@redhat.com> wrote:
> > Ian Campbell <Ian.Campbell@citrix.com> writes:
> >
> >> On Wed, 2013-10-16 at 12:49 +0200, Markus Armbruster wrote:
> >>> Ian Campbell <Ian.Campbell@citrix.com> writes:
> >>>
> >>> > On Wed, 2013-10-16 at 10:54 +0100, Jan Beulich wrote:
> >>> >> >>> On 16.10.13 at 08:30, "Gonglei (Arei)" <arei.gonglei@huawei.com>
> wrote:
> >>> >> > --- hvmloader/acpi/Makefile	2013-10-16 11:51:53.000000000 +0800
> >>> >> > +++ hvmloader_new//acpi/Makefile	2013-10-16
> 11:51:58.000000000 +0800
> >>> >> > @@ -36,18 +36,34 @@
> >>> >> >
> >>> >> >  dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
> >>> >> >  	awk 'NR > 1 {print s} {s=$$0}' $< > $@
> >>> >> > -	./mk_dsdt --dm-version qemu-xen >> $@
> >>> >> > +	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@
> >>> >>
> >>> >> This must never be done - if someone hits Ctrl-C in the middle of
> >>> >> this, you'll have a modified but incomplete generated file. You
> >>> >> either need to use properly chained rules, or do all output to a
> >>> >> temporary file which you rename as the last step.
> >>> >>
> >>> >> I realize that the problem existed before your change, but you
> >>> >> making it worse requires doing it properly now.
> >>> >
> >>> > The correct way to do this is to generate to a temporary file and then
> >>> > use $(call move-if-changed,$@.tmp,$@). There are a bunch of examples
> in
> >>> > tools/libxl/Makefile and elsewhere.
> >>>
> >>> Quoting the GNU make manual[*]:
> >>>
> >>>     So generally the right thing to do is to delete the target file if
> >>>     the recipe fails after beginning to change the file.  make will do
> >>>     this if .DELETE_ON_ERROR appears as a target.  This is almost
> always
> >>>     what you want make to do, but it is not historical practice; so for
> >>>     compatibility, you must explicitly request it.
> >>>
> >>> In my opinion, every Makefile should request it.
> >>>
> >>> [*] https://www.gnu.org/software/make/manual/html_node/Errors.html
> >>
> >> I think this is somewhat orthogonal to the use of move-if-changed which
> >> is there to ensure that the timestamp doesn't change gratuitously and
> >> cause a load of knock on rebuilds even though the regenerated content is
> >> identical.
> >
> > Yes.  I was latching onto the "if someone hits Ctrl-C in the middle of
> > this, you'll have a modified but incomplete generated file" phrase.
> 
> Right, but Ctrl-C is only the soft way of failing. If the system
> happens to crash at the right moment, make won't be able to go
> and delete the file anymore. IOW the move-if-changed approach
> covers a wider range of situations _and_ had the benefit of
> avoiding unnecessary rebuilds.
> 
> Jan


[-- Attachment #2: EJ0_ACPI_PCI_Hotplug.patch --]
[-- Type: application/octet-stream, Size: 24071 bytes --]

From 02625056146e443ba3092dcca6cf27c775f2e621 Mon Sep 17 00:00:00 2001
From: gaowei <gao.gaowei@huawei.com>
Date: Tue, 22 Oct 2013 11:42:53 +0800
Subject: [PATCH] Hvmloader: Modify ACPI to only supply _EJ0 methods for
 PCIslots that support hotplug by runtime patching

 In Xen platform, after using upstream qemu, the all of pci devices will show hotplug in the windows guest.
 In this situation, the windows guest may occur blue screen when VM' user click the icon of VGA card for trying unplug VGA card.
 However, we don't hope VM's user can do such dangerous operation, and showing all pci devices inside the guest OS is unfriendly.
 This is done by runtime patching:
  - Rename _EJ0 methods for PCI slots in DSDT to EJ0_:note that this has the same checksum, but is ignored by OSPM.
  - At compile time, look for these methods in ASL source,find the matching AML, and store the offsets of these methods in a table named aml_ej0_data.
  - At run time, go over aml_ej0_data, check which slots not support hotplug and patch the ACPI table, replacing _EJ0 with EJ0_.

Signed-off-by: gaowei <gao.gaowei@huawei.com>
Signed-off-by: gonglei <arei.gonglei@huawei.com>
---
 tools/firmware/hvmloader/acpi/Makefile             |  46 ++-
 tools/firmware/hvmloader/acpi/acpi2_0.h            |   5 +
 tools/firmware/hvmloader/acpi/build.c              |  24 +-
 tools/firmware/hvmloader/acpi/dsdt.asl             |   1 +
 tools/firmware/hvmloader/acpi/mk_dsdt.c            |   2 +
 tools/firmware/hvmloader/mkhex                     |   0
 tools/firmware/hvmloader/ovmf.c                    |   6 +-
 tools/firmware/hvmloader/rombios.c                 |   4 +
 tools/firmware/hvmloader/seabios.c                 |   8 +
 tools/firmware/hvmloader/tools/acpi_extract.py     | 308 +++++++++++++++++++++
 .../hvmloader/tools/acpi_extract_preprocess.py     |  41 +++
 11 files changed, 431 insertions(+), 14 deletions(-)
 mode change 100755 => 100644 tools/firmware/hvmloader/mkhex
 create mode 100644 tools/firmware/hvmloader/tools/acpi_extract.py
 create mode 100644 tools/firmware/hvmloader/tools/acpi_extract_preprocess.py

diff --git a/tools/firmware/hvmloader/acpi/Makefile b/tools/firmware/hvmloader/acpi/Makefile
index 2c50851..8b3f7ac 100644
--- a/tools/firmware/hvmloader/acpi/Makefile
+++ b/tools/firmware/hvmloader/acpi/Makefile
@@ -24,30 +24,46 @@ OBJS  = $(patsubst %.c,%.o,$(C_SRC))
 CFLAGS += $(CFLAGS_xeninclude)
 
 vpath iasl $(PATH)
+vpath python $(PATH)
+
+.DELETE_ON_ERROR:$(filter dsdt_%.c,$(C_SRC))
+
 all: acpi.a
 
 ssdt_s3.h ssdt_s4.h ssdt_pm.h ssdt_tpm.h: %.h: %.asl iasl
 	iasl -vs -p $* -tc $<
-	sed -e 's/AmlCode/$*/g' $*.hex >$@
+	sed -e 's/AmlCode/$*/g' $*.hex >$@.tmp
+	$(call move-if-changed,$@.tmp $@)
 	rm -f $*.hex $*.aml
 
 mk_dsdt: mk_dsdt.c
 	$(HOSTCC) $(HOSTCFLAGS) $(CFLAGS_xeninclude) -o $@ mk_dsdt.c
 
 dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
-	awk 'NR > 1 {print s} {s=$$0}' $< > $@
-	./mk_dsdt --dm-version qemu-xen >> $@
-
+	awk 'NR > 1 {print s} {s=$$0}' $< > $@.tmp
+	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@.tmp
+	./mk_dsdt --dm-version qemu-xen >> $@.tmp
+	sed -i 's/aml_ej0_name/dsdt_anycpu_qemu_xen_aml_ej0_name/g' $@.tmp
+	sed -i 's/aml_adr_dword/dsdt_anycpu_qemu_xen_aml_adr_dword/g' $@.tmp
+	$(call move-if-changed,$@.tmp $@)
+	
 # NB. awk invocation is a portable alternative to 'head -n -1'
 dsdt_%cpu.asl: dsdt.asl mk_dsdt
-	awk 'NR > 1 {print s} {s=$$0}' $< > $@
-	./mk_dsdt --maxcpu $*  >> $@
+	awk 'NR > 1 {print s} {s=$$0}' $< > $@.tmp
+	sed -i 's/AmlCode/dsdt_$*cpu/g' $@.tmp
+	./mk_dsdt --maxcpu $*  >> $@.tmp
+	$(call move-if-changed,$@.tmp $@)
 
-$(filter dsdt_%.c,$(C_SRC)): %.c: iasl %.asl
-	iasl -vs -p $* -tc $*.asl
-	sed -e 's/AmlCode/$*/g' $*.hex >$@
-	echo "int $*_len=sizeof($*);" >>$@
-	rm -f $*.aml $*.hex
+$(filter dsdt_%.c,$(C_SRC)): %.c: iasl python %.asl
+	cpp -P $*.asl > $*.asl.i.orig
+	python ../tools/acpi_extract_preprocess.py $*.asl.i.orig > $*.asl.i
+	iasl -vs -l -tc -p $* $*.asl.i
+	python ../tools/acpi_extract.py $*.lst > $@.tmp
+	echo "int $*_len=sizeof($*);" >>$@.tmp
+	if grep -q "$*_aml_ej0_name" $@.tmp; then echo "int $*_aml_ej0_name_len=sizeof($*_aml_ej0_name);" >>$@.tmp; fi
+	if grep -q "$*_aml_adr_dword" $@.tmp; then echo "int $*_aml_adr_dword_len=sizeof($*_aml_adr_dword);" >>$@.tmp;fi
+	$(call move-if-changed,$@.tmp $@)
+	rm -f $*.aml $*.hex $*.asl.i.orig $*.asl.i $*.lst
 
 iasl:
 	@echo
@@ -57,6 +73,12 @@ iasl:
 	@echo 
 	@exit 1
 
+python:
+	@echo
+	@echo "python is needed"
+	@echo
+	@exit 1
+
 build.o: ssdt_s3.h ssdt_s4.h ssdt_pm.h ssdt_tpm.h
 
 acpi.a: $(OBJS)
@@ -64,7 +86,7 @@ acpi.a: $(OBJS)
 
 clean:
 	rm -rf *.a *.o $(IASL_VER) $(IASL_VER).tar.gz $(DEPS)
-	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl
+	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl *.asl.i *.asl.i.orig *.lst *.tmp
 
 install: all
 
diff --git a/tools/firmware/hvmloader/acpi/acpi2_0.h b/tools/firmware/hvmloader/acpi/acpi2_0.h
index 7b22d80..d0c83b8 100644
--- a/tools/firmware/hvmloader/acpi/acpi2_0.h
+++ b/tools/firmware/hvmloader/acpi/acpi2_0.h
@@ -396,6 +396,11 @@ struct acpi_config {
     int dsdt_anycpu_len;
     unsigned char *dsdt_15cpu;
     int dsdt_15cpu_len;
+    unsigned short *aml_ej0_name;
+    unsigned short *aml_adr_dword;
+    int aml_ej0_name_len;
+    int aml_adr_dword_len;
+    
 };
 
 void acpi_build_tables(struct acpi_config *config, unsigned int physical);
diff --git a/tools/firmware/hvmloader/acpi/build.c b/tools/firmware/hvmloader/acpi/build.c
index f1dd3f0..35681aa 100644
--- a/tools/firmware/hvmloader/acpi/build.c
+++ b/tools/firmware/hvmloader/acpi/build.c
@@ -30,6 +30,9 @@
 #define align16(sz)        (((sz) + 15) & ~15)
 #define fixed_strcpy(d, s) strncpy((d), (s), sizeof(d))
 
+
+#define PCI_RMV_BASE 0xae0c
+
 extern struct acpi_20_rsdp Rsdp;
 extern struct acpi_20_rsdt Rsdt;
 extern struct acpi_20_xsdt Xsdt;
@@ -404,6 +407,7 @@ void acpi_build_tables(struct acpi_config *config, unsigned int physical)
     unsigned char       *dsdt;
     unsigned long        secondary_tables[ACPI_MAX_SECONDARY_TABLES];
     int                  nr_secondaries, i;
+    unsigned int rmvc_pcrm = 0;
 
     /* Allocate and initialise the acpi info area. */
     mem_hole_populate_ram(ACPI_INFO_PHYSICAL_ADDRESS >> PAGE_SHIFT, 1);
@@ -438,9 +442,27 @@ void acpi_build_tables(struct acpi_config *config, unsigned int physical)
         dsdt = mem_alloc(config->dsdt_anycpu_len, 16);
         if (!dsdt) goto oom;
         memcpy(dsdt, config->dsdt_anycpu, config->dsdt_anycpu_len);
-        nr_processor_objects = HVM_MAX_VCPUS;
+        if(config->aml_adr_dword_len && config->aml_ej0_name_len &&
+            (config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]) == config->aml_ej0_name_len/sizeof(config->aml_ej0_name[0])))
+        {
+            rmvc_pcrm = inl(PCI_RMV_BASE); 
+            printf("rmvc_pcrm is %x\n", rmvc_pcrm);
+            for(i = 0;  i < config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]); i ++)
+            {
+                /* Slot is in byte 2 in _ADR */
+                unsigned char slot = dsdt[config->aml_adr_dword[i] + 2] & 0x1F;
+                /* Sanity check */
+                if (memcmp(dsdt + config->aml_ej0_name[i], "_EJ0", 4)) {
+                    goto oom;
+                }
+                if (!(rmvc_pcrm & (0x1 << slot))) {
+                    memcpy(dsdt + config->aml_ej0_name[i], "EJ0_", 4);
+                }
+            }
+        }
     }
 
+    nr_processor_objects = HVM_MAX_VCPUS;
     /*
      * N.B. ACPI 1.0 operating systems may not handle FADT with revision 2
      * or above properly, notably Windows 2000, which tries to copy FADT
diff --git a/tools/firmware/hvmloader/acpi/dsdt.asl b/tools/firmware/hvmloader/acpi/dsdt.asl
index 247a8ad..1e7695b 100644
--- a/tools/firmware/hvmloader/acpi/dsdt.asl
+++ b/tools/firmware/hvmloader/acpi/dsdt.asl
@@ -16,6 +16,7 @@
  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  * Place - Suite 330, Boston, MA 02111-1307 USA.
  */
+ACPI_EXTRACT_ALL_CODE AmlCode
 
 DefinitionBlock ("DSDT.aml", "DSDT", 2, "Xen", "HVM", 0)
 {
diff --git a/tools/firmware/hvmloader/acpi/mk_dsdt.c b/tools/firmware/hvmloader/acpi/mk_dsdt.c
index 996f30b..4180801 100644
--- a/tools/firmware/hvmloader/acpi/mk_dsdt.c
+++ b/tools/firmware/hvmloader/acpi/mk_dsdt.c
@@ -368,7 +368,9 @@ int main(int argc, char **argv)
         /* hotplug_slot */
         for (slot = 1; slot <= 31; slot++) {
             push_block("Device", "S%i", slot); {
+                printf("ACPI_EXTRACT_NAME_DWORD_CONST aml_adr_dword\n");
                 stmt("Name", "_ADR, %#06x0000", slot);
+                printf("ACPI_EXTRACT_METHOD_STRING aml_ej0_name\n");
                 push_block("Method", "_EJ0,1"); {
                     stmt("Store", "ShiftLeft(1, %#06x), B0EJ", slot);
                     stmt("Return", "0x0");
diff --git a/tools/firmware/hvmloader/mkhex b/tools/firmware/hvmloader/mkhex
old mode 100755
new mode 100644
diff --git a/tools/firmware/hvmloader/ovmf.c b/tools/firmware/hvmloader/ovmf.c
index ee4cbbf..27ff0b5 100644
--- a/tools/firmware/hvmloader/ovmf.c
+++ b/tools/firmware/hvmloader/ovmf.c
@@ -79,7 +79,11 @@ static void ovmf_acpi_build_tables(void)
         .dsdt_anycpu = dsdt_anycpu,
         .dsdt_anycpu_len = dsdt_anycpu_len,
         .dsdt_15cpu = NULL, 
-        .dsdt_15cpu_len = 0
+        .dsdt_15cpu_len = 0,
+        .aml_ej0_name = NULL,
+        .aml_adr_dword = NULL,
+        .aml_ej0_name_len = 0,
+        .aml_adr_dword_len = 0,
     };
 
     acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
diff --git a/tools/firmware/hvmloader/rombios.c b/tools/firmware/hvmloader/rombios.c
index 810bd24..803c9fa 100644
--- a/tools/firmware/hvmloader/rombios.c
+++ b/tools/firmware/hvmloader/rombios.c
@@ -179,6 +179,10 @@ static void rombios_acpi_build_tables(void)
         .dsdt_anycpu_len = dsdt_anycpu_len,
         .dsdt_15cpu = dsdt_15cpu,
         .dsdt_15cpu_len = dsdt_15cpu_len,
+        .aml_ej0_name = NULL,
+        .aml_adr_dword = NULL,
+        .aml_ej0_name_len = 0,
+        .aml_adr_dword_len = 0,
     };
 
     acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
diff --git a/tools/firmware/hvmloader/seabios.c b/tools/firmware/hvmloader/seabios.c
index dd7dfbe..ca01d27 100644
--- a/tools/firmware/hvmloader/seabios.c
+++ b/tools/firmware/hvmloader/seabios.c
@@ -33,6 +33,10 @@
 
 extern unsigned char dsdt_anycpu_qemu_xen[];
 extern int dsdt_anycpu_qemu_xen_len;
+extern unsigned short dsdt_anycpu_qemu_xen_aml_ej0_name[];
+extern unsigned short dsdt_anycpu_qemu_xen_aml_adr_dword[];
+extern int dsdt_anycpu_qemu_xen_aml_ej0_name_len;
+extern int dsdt_anycpu_qemu_xen_aml_adr_dword_len;
 
 struct seabios_info {
     char signature[14]; /* XenHVMSeaBIOS\0 */
@@ -99,6 +103,10 @@ static void seabios_acpi_build_tables(void)
         .dsdt_anycpu_len = dsdt_anycpu_qemu_xen_len,
         .dsdt_15cpu = NULL,
         .dsdt_15cpu_len = 0,
+        .aml_ej0_name = dsdt_anycpu_qemu_xen_aml_ej0_name,
+        .aml_adr_dword = dsdt_anycpu_qemu_xen_aml_adr_dword,
+        .aml_ej0_name_len = dsdt_anycpu_qemu_xen_aml_ej0_name_len,
+        .aml_adr_dword_len = dsdt_anycpu_qemu_xen_aml_adr_dword_len,
     };
 
     acpi_build_tables(&config, rsdp);
diff --git a/tools/firmware/hvmloader/tools/acpi_extract.py b/tools/firmware/hvmloader/tools/acpi_extract.py
new file mode 100644
index 0000000..4fa51f7
--- /dev/null
+++ b/tools/firmware/hvmloader/tools/acpi_extract.py
@@ -0,0 +1,308 @@
+#!/usr/bin/python
+# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+# Process mixed ASL/AML listing (.lst file) produced by iasl -l
+# Locate and execute ACPI_EXTRACT directives, output offset info
+# 
+# Documentation of ACPI_EXTRACT_* directive tags:
+# 
+# These directive tags output offset information from AML for BIOS runtime
+# table generation.
+# Each directive is of the form:
+# ACPI_EXTRACT_<TYPE> <array_name> <Operator> (...)
+# and causes the extractor to create an array
+# named <array_name> with offset, in the generated AML,
+# of an object of a given type in the following <Operator>.
+# 
+# A directive must fit on a single code line.
+# 
+# Object type in AML is verified, a mismatch causes a build failure.
+# 
+# Directives and operators currently supported are:
+# ACPI_EXTRACT_NAME_DWORD_CONST - extract a Dword Const object from Name()
+# ACPI_EXTRACT_NAME_WORD_CONST - extract a Word Const object from Name()
+# ACPI_EXTRACT_NAME_BYTE_CONST - extract a Byte Const object from Name()
+# ACPI_EXTRACT_METHOD_STRING - extract a NameString from Method()
+# ACPI_EXTRACT_NAME_STRING - extract a NameString from Name()
+# ACPI_EXTRACT_PROCESSOR_START - start of Processor() block
+# ACPI_EXTRACT_PROCESSOR_STRING - extract a NameString from Processor()
+# ACPI_EXTRACT_PROCESSOR_END - offset at last byte of Processor() + 1
+# ACPI_EXTRACT_PKG_START - start of Package block
+#
+# ACPI_EXTRACT_ALL_CODE - create an array storing the generated AML bytecode
+# 
+# ACPI_EXTRACT is not allowed anywhere else in code, except in comments.
+
+import re;
+import sys;
+import fileinput;
+
+aml = []
+asl = []
+output = {}
+debug = ""
+
+class asl_line:
+    line = None
+    lineno = None
+    aml_offset = None
+
+def die(diag):
+    sys.stderr.write("Error: %s; %s\n" % (diag, debug))
+    sys.exit(1)
+    
+#Store an ASL command, matching AML offset, and input line (for debugging)
+def add_asl(lineno, line):
+    l = asl_line()
+    l.line = line
+    l.lineno = lineno
+    l.aml_offset = len(aml)
+    asl.append(l)
+
+#Store an AML byte sequence
+#Verify that offset output by iasl matches # of bytes so far
+def add_aml(offset, line):
+    o = int(offset, 16);
+    # Sanity check: offset must match size of code so far
+    if (o != len(aml)):
+        die("Offset 0x%x != 0x%x" % (o, len(aml)))
+    # Strip any trailing dots and ASCII dump after "
+    line = re.sub(r'\s*\.*\s*".*$',"", line)
+    # Strip traling whitespace
+    line = re.sub(r'\s+$',"", line)
+    # Strip leading whitespace
+    line = re.sub(r'^\s+',"", line)
+    # Split on whitespace
+    code = re.split(r'\s+', line)
+    for c in code:
+        # Require a legal hex number, two digits
+        if (not(re.search(r'^[0-9A-Fa-f][0-9A-Fa-f]$', c))):
+            die("Unexpected octet %s" % c);
+        aml.append(int(c, 16));
+
+# Process aml bytecode array, decoding AML
+def aml_pkglen_bytes(offset):
+    # PkgLength can be multibyte. Bits 8-7 give the # of extra bytes.
+    pkglenbytes = aml[offset] >> 6;
+    return pkglenbytes + 1
+
+def aml_pkglen(offset):
+    pkgstart = offset
+    pkglenbytes = aml_pkglen_bytes(offset)
+    pkglen = aml[offset] & 0x3F
+    # If multibyte, first nibble only uses bits 0-3
+    if ((pkglenbytes > 0) and (pkglen & 0x30)):
+        die("PkgLen bytes 0x%x but first nibble 0x%x expected 0x0X" %
+            (pkglen, pkglen))
+    offset += 1
+    pkglenbytes -= 1
+    for i in range(pkglenbytes):
+        pkglen |= aml[offset + i] << (i * 8 + 4)
+    if (len(aml) < pkgstart + pkglen):
+        die("PckgLen 0x%x at offset 0x%x exceeds AML size 0x%x" %
+            (pkglen, offset, len(aml)))
+    return pkglen
+
+# Given method offset, find its NameString offset
+def aml_method_string(offset):
+    #0x14 MethodOp PkgLength NameString MethodFlags TermList
+    if (aml[offset] != 0x14):
+        die( "Method offset 0x%x: expected 0x14 actual 0x%x" %
+             (offset, aml[offset]));
+    offset += 1;
+    pkglenbytes = aml_pkglen_bytes(offset)
+    offset += pkglenbytes;
+    return offset;
+
+# Given name offset, find its NameString offset
+def aml_name_string(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x08):
+        die( "Name offset 0x%x: expected 0x08 actual 0x%x" %
+             (offset, aml[offset]));
+    offset += 1
+    # Block Name Modifier. Skip it.
+    if (aml[offset] == 0x5c or aml[offset] == 0x5e):
+        offset += 1
+    return offset;
+
+# Given data offset, find dword const offset
+def aml_data_dword_const(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x0C):
+        die( "Name offset 0x%x: expected 0x0C actual 0x%x" %
+             (offset, aml[offset]));
+    return offset + 1;
+
+# Given data offset, find word const offset
+def aml_data_word_const(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x0B):
+        die( "Name offset 0x%x: expected 0x0B actual 0x%x" %
+             (offset, aml[offset]));
+    return offset + 1;
+
+# Given data offset, find byte const offset
+def aml_data_byte_const(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x0A):
+        die( "Name offset 0x%x: expected 0x0A actual 0x%x" %
+             (offset, aml[offset]));
+    return offset + 1;
+
+# Given name offset, find dword const offset
+def aml_name_dword_const(offset):
+    return aml_data_dword_const(aml_name_string(offset) + 4)
+
+# Given name offset, find word const offset
+def aml_name_word_const(offset):
+    return aml_data_word_const(aml_name_string(offset) + 4)
+
+# Given name offset, find byte const offset
+def aml_name_byte_const(offset):
+    return aml_data_byte_const(aml_name_string(offset) + 4)
+
+def aml_processor_start(offset):
+    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
+    if ((aml[offset] != 0x5B) or (aml[offset + 1] != 0x83)):
+        die( "Name offset 0x%x: expected 0x5B 0x83 actual 0x%x 0x%x" %
+             (offset, aml[offset], aml[offset + 1]));
+    return offset
+
+def aml_processor_string(offset):
+    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
+    start = aml_processor_start(offset)
+    offset += 2
+    pkglenbytes = aml_pkglen_bytes(offset)
+    offset += pkglenbytes
+    return offset
+
+def aml_processor_end(offset):
+    start = aml_processor_start(offset)
+    offset += 2
+    pkglenbytes = aml_pkglen_bytes(offset)
+    pkglen = aml_pkglen(offset)
+    return offset + pkglen
+
+def aml_package_start(offset):
+    offset = aml_name_string(offset) + 4
+    # 0x12 PkgLength NumElements PackageElementList
+    if (aml[offset] != 0x12):
+        die( "Name offset 0x%x: expected 0x12 actual 0x%x" %
+             (offset, aml[offset]));
+    offset += 1
+    return offset + aml_pkglen_bytes(offset) + 1
+
+lineno = 0
+for line in fileinput.input():
+    # Strip trailing newline
+    line = line.rstrip();
+    # line number and debug string to output in case of errors
+    lineno = lineno + 1
+    debug = "input line %d: %s" % (lineno, line)
+    #ASL listing: space, then line#, then ...., then code
+    pasl = re.compile('^\s+([0-9]+)\.\.\.\.\s*')
+    m = pasl.search(line)
+    if (m):
+        add_asl(lineno, pasl.sub("", line));
+    # AML listing: offset in hex, then ...., then code
+    paml = re.compile('^([0-9A-Fa-f]+)\.\.\.\.\s*')
+    m = paml.search(line)
+    if (m):
+        add_aml(m.group(1), paml.sub("", line))
+
+# Now go over code
+# Track AML offset of a previous non-empty ASL command
+prev_aml_offset = -1
+for i in range(len(asl)):
+    debug = "input line %d: %s" % (asl[i].lineno, asl[i].line)
+
+    l = asl[i].line
+
+    # skip if not an extract directive
+    a = len(re.findall(r'ACPI_EXTRACT', l))
+    if (not a):
+        # If not empty, store AML offset. Will be used for sanity checks
+        # IASL seems to put {}. at random places in the listing.
+        # Ignore any non-words for the purpose of this test.
+        m = re.search(r'\w+', l)
+        if (m):
+                prev_aml_offset = asl[i].aml_offset
+        continue
+
+    if (a > 1):
+        die("Expected at most one ACPI_EXTRACT per line, actual %d" % a)
+
+    mext = re.search(r'''
+                      ^\s* # leading whitespace
+                      /\*\s* # start C comment
+                      (ACPI_EXTRACT_\w+) # directive: group(1)
+                      \s+ # whitspace separates directive from array name
+                      (\w+) # array name: group(2)
+                      \s*\*/ # end of C comment
+                      \s*$ # trailing whitespace
+                      ''', l, re.VERBOSE)
+    if (not mext):
+        die("Stray ACPI_EXTRACT in input")
+
+    # previous command must have produced some AML,
+    # otherwise we are in a middle of a block
+    if (prev_aml_offset == asl[i].aml_offset):
+        die("ACPI_EXTRACT directive in the middle of a block")
+
+    directive = mext.group(1)
+    array = mext.group(2)
+    offset = asl[i].aml_offset
+
+    if (directive == "ACPI_EXTRACT_ALL_CODE"):
+        if array in output:
+            die("%s directive used more than once" % directive)
+        output[array] = aml
+        continue
+    if (directive == "ACPI_EXTRACT_NAME_DWORD_CONST"):
+        offset = aml_name_dword_const(offset)
+    elif (directive == "ACPI_EXTRACT_NAME_WORD_CONST"):
+        offset = aml_name_word_const(offset)
+    elif (directive == "ACPI_EXTRACT_NAME_BYTE_CONST"):
+        offset = aml_name_byte_const(offset)
+    elif (directive == "ACPI_EXTRACT_NAME_STRING"):
+        offset = aml_name_string(offset)
+    elif (directive == "ACPI_EXTRACT_METHOD_STRING"):
+        offset = aml_method_string(offset)
+    elif (directive == "ACPI_EXTRACT_PROCESSOR_START"):
+        offset = aml_processor_start(offset)
+    elif (directive == "ACPI_EXTRACT_PROCESSOR_STRING"):
+        offset = aml_processor_string(offset)
+    elif (directive == "ACPI_EXTRACT_PROCESSOR_END"):
+        offset = aml_processor_end(offset)
+    elif (directive == "ACPI_EXTRACT_PKG_START"):
+        offset = aml_package_start(offset)
+    else:
+        die("Unsupported directive %s" % directive)
+
+    if array not in output:
+        output[array] = []
+    output[array].append(offset)
+
+debug = "at end of file"
+
+def get_value_type(maxvalue):
+    #Use type large enough to fit the table
+    if (maxvalue >= 0x10000):
+            return "int"
+    elif (maxvalue >= 0x100):
+            return "short"
+    else:
+            return "char"
+
+# Pretty print output
+for array in output.keys():
+    otype = get_value_type(max(output[array]))
+    odata = []
+    for value in output[array]:
+        odata.append("0x%x" % value)
+    sys.stdout.write("unsigned %s %s[] = {\n" % (otype, array))
+    sys.stdout.write(",\n".join(odata))
+    sys.stdout.write('\n};\n');
diff --git a/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py b/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py
new file mode 100644
index 0000000..4ae364e
--- /dev/null
+++ b/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py
@@ -0,0 +1,41 @@
+#!/usr/bin/python
+# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+# Read a preprocessed ASL listing and put each ACPI_EXTRACT
+# directive in a comment, to make iasl skip it.
+# We also put each directive on a new line, the machinery
+# in tools/acpi_extract.py requires this.
+
+import re;
+import sys;
+import fileinput;
+
+def die(diag):
+    sys.stderr.write("Error: %s\n" % (diag))
+    sys.exit(1)
+
+# Note: () around pattern make split return matched string as part of list
+psplit = re.compile(r''' (
+                          \b # At word boundary
+                          ACPI_EXTRACT_\w+ # directive
+                          \s+ # some whitespace
+                          \w+ # array name
+                         )''', re.VERBOSE);
+
+lineno = 0
+for line in fileinput.input():
+    # line number and debug string to output in case of errors
+    lineno = lineno + 1
+    debug = "input line %d: %s" % (lineno, line.rstrip())
+
+    s = psplit.split(line);
+    # The way split works, each odd item is the matching ACPI_EXTRACT directive.
+    # Put each in a comment, and on a line by itself.
+    for i in range(len(s)):
+        if (i % 2):
+            sys.stdout.write("\n/* %s */\n" % s[i])
+        else:
+            sys.stdout.write(s[i])
+
-- 
1.8.3.4


[-- Attachment #3: 4.3.0.patch --]
[-- Type: application/octet-stream, Size: 23126 bytes --]

From ba9f86748620e61768c59b2efcf399b8fd6b435c Mon Sep 17 00:00:00 2001
From: gaowei <gao.gaowei@huawei.com>
Date: Tue, 22 Oct 2013 11:56:46 +0800
Subject: [PATCH] for Test

Signed-off-by: gaowei <gao.gaowei@huawei.com>
---
 tools/firmware/hvmloader/acpi/Makefile             |  46 ++-
 tools/firmware/hvmloader/acpi/acpi2_0.h            |   5 +
 tools/firmware/hvmloader/acpi/build.c              |  24 +-
 tools/firmware/hvmloader/acpi/dsdt.asl             |   1 +
 tools/firmware/hvmloader/acpi/mk_dsdt.c            |   2 +
 tools/firmware/hvmloader/mkhex                     |   0
 tools/firmware/hvmloader/ovmf.c                    |   6 +-
 tools/firmware/hvmloader/rombios.c                 |   4 +
 tools/firmware/hvmloader/seabios.c                 |   8 +
 tools/firmware/hvmloader/tools/acpi_extract.py     | 308 +++++++++++++++++++++
 .../hvmloader/tools/acpi_extract_preprocess.py     |  41 +++
 11 files changed, 431 insertions(+), 14 deletions(-)
 mode change 100755 => 100644 tools/firmware/hvmloader/mkhex
 create mode 100644 tools/firmware/hvmloader/tools/acpi_extract.py
 create mode 100644 tools/firmware/hvmloader/tools/acpi_extract_preprocess.py

diff --git a/tools/firmware/hvmloader/acpi/Makefile b/tools/firmware/hvmloader/acpi/Makefile
index 2c50851..8b3f7ac 100644
--- a/tools/firmware/hvmloader/acpi/Makefile
+++ b/tools/firmware/hvmloader/acpi/Makefile
@@ -24,30 +24,46 @@ OBJS  = $(patsubst %.c,%.o,$(C_SRC))
 CFLAGS += $(CFLAGS_xeninclude)
 
 vpath iasl $(PATH)
+vpath python $(PATH)
+
+.DELETE_ON_ERROR:$(filter dsdt_%.c,$(C_SRC))
+
 all: acpi.a
 
 ssdt_s3.h ssdt_s4.h ssdt_pm.h ssdt_tpm.h: %.h: %.asl iasl
 	iasl -vs -p $* -tc $<
-	sed -e 's/AmlCode/$*/g' $*.hex >$@
+	sed -e 's/AmlCode/$*/g' $*.hex >$@.tmp
+	$(call move-if-changed,$@.tmp $@)
 	rm -f $*.hex $*.aml
 
 mk_dsdt: mk_dsdt.c
 	$(HOSTCC) $(HOSTCFLAGS) $(CFLAGS_xeninclude) -o $@ mk_dsdt.c
 
 dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
-	awk 'NR > 1 {print s} {s=$$0}' $< > $@
-	./mk_dsdt --dm-version qemu-xen >> $@
-
+	awk 'NR > 1 {print s} {s=$$0}' $< > $@.tmp
+	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@.tmp
+	./mk_dsdt --dm-version qemu-xen >> $@.tmp
+	sed -i 's/aml_ej0_name/dsdt_anycpu_qemu_xen_aml_ej0_name/g' $@.tmp
+	sed -i 's/aml_adr_dword/dsdt_anycpu_qemu_xen_aml_adr_dword/g' $@.tmp
+	$(call move-if-changed,$@.tmp $@)
+	
 # NB. awk invocation is a portable alternative to 'head -n -1'
 dsdt_%cpu.asl: dsdt.asl mk_dsdt
-	awk 'NR > 1 {print s} {s=$$0}' $< > $@
-	./mk_dsdt --maxcpu $*  >> $@
+	awk 'NR > 1 {print s} {s=$$0}' $< > $@.tmp
+	sed -i 's/AmlCode/dsdt_$*cpu/g' $@.tmp
+	./mk_dsdt --maxcpu $*  >> $@.tmp
+	$(call move-if-changed,$@.tmp $@)
 
-$(filter dsdt_%.c,$(C_SRC)): %.c: iasl %.asl
-	iasl -vs -p $* -tc $*.asl
-	sed -e 's/AmlCode/$*/g' $*.hex >$@
-	echo "int $*_len=sizeof($*);" >>$@
-	rm -f $*.aml $*.hex
+$(filter dsdt_%.c,$(C_SRC)): %.c: iasl python %.asl
+	cpp -P $*.asl > $*.asl.i.orig
+	python ../tools/acpi_extract_preprocess.py $*.asl.i.orig > $*.asl.i
+	iasl -vs -l -tc -p $* $*.asl.i
+	python ../tools/acpi_extract.py $*.lst > $@.tmp
+	echo "int $*_len=sizeof($*);" >>$@.tmp
+	if grep -q "$*_aml_ej0_name" $@.tmp; then echo "int $*_aml_ej0_name_len=sizeof($*_aml_ej0_name);" >>$@.tmp; fi
+	if grep -q "$*_aml_adr_dword" $@.tmp; then echo "int $*_aml_adr_dword_len=sizeof($*_aml_adr_dword);" >>$@.tmp;fi
+	$(call move-if-changed,$@.tmp $@)
+	rm -f $*.aml $*.hex $*.asl.i.orig $*.asl.i $*.lst
 
 iasl:
 	@echo
@@ -57,6 +73,12 @@ iasl:
 	@echo 
 	@exit 1
 
+python:
+	@echo
+	@echo "python is needed"
+	@echo
+	@exit 1
+
 build.o: ssdt_s3.h ssdt_s4.h ssdt_pm.h ssdt_tpm.h
 
 acpi.a: $(OBJS)
@@ -64,7 +86,7 @@ acpi.a: $(OBJS)
 
 clean:
 	rm -rf *.a *.o $(IASL_VER) $(IASL_VER).tar.gz $(DEPS)
-	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl
+	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl *.asl.i *.asl.i.orig *.lst *.tmp
 
 install: all
 
diff --git a/tools/firmware/hvmloader/acpi/acpi2_0.h b/tools/firmware/hvmloader/acpi/acpi2_0.h
index 7b22d80..d0c83b8 100644
--- a/tools/firmware/hvmloader/acpi/acpi2_0.h
+++ b/tools/firmware/hvmloader/acpi/acpi2_0.h
@@ -396,6 +396,11 @@ struct acpi_config {
     int dsdt_anycpu_len;
     unsigned char *dsdt_15cpu;
     int dsdt_15cpu_len;
+    unsigned short *aml_ej0_name;
+    unsigned short *aml_adr_dword;
+    int aml_ej0_name_len;
+    int aml_adr_dword_len;
+    
 };
 
 void acpi_build_tables(struct acpi_config *config, unsigned int physical);
diff --git a/tools/firmware/hvmloader/acpi/build.c b/tools/firmware/hvmloader/acpi/build.c
index 7281b97..e3a83d8 100644
--- a/tools/firmware/hvmloader/acpi/build.c
+++ b/tools/firmware/hvmloader/acpi/build.c
@@ -30,6 +30,9 @@
 #define align16(sz)        (((sz) + 15) & ~15)
 #define fixed_strcpy(d, s) strncpy((d), (s), sizeof(d))
 
+
+#define PCI_RMV_BASE 0xae0c
+
 extern struct acpi_20_rsdp Rsdp;
 extern struct acpi_20_rsdt Rsdt;
 extern struct acpi_20_xsdt Xsdt;
@@ -402,6 +405,7 @@ void acpi_build_tables(struct acpi_config *config, unsigned int physical)
     unsigned char       *dsdt;
     unsigned long        secondary_tables[ACPI_MAX_SECONDARY_TABLES];
     int                  nr_secondaries, i;
+    unsigned int rmvc_pcrm = 0;
 
     /* Allocate and initialise the acpi info area. */
     mem_hole_populate_ram(ACPI_INFO_PHYSICAL_ADDRESS >> PAGE_SHIFT, 1);
@@ -436,9 +440,27 @@ void acpi_build_tables(struct acpi_config *config, unsigned int physical)
         dsdt = mem_alloc(config->dsdt_anycpu_len, 16);
         if (!dsdt) goto oom;
         memcpy(dsdt, config->dsdt_anycpu, config->dsdt_anycpu_len);
-        nr_processor_objects = HVM_MAX_VCPUS;
+        if(config->aml_adr_dword_len && config->aml_ej0_name_len &&
+            (config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]) == config->aml_ej0_name_len/sizeof(config->aml_ej0_name[0])))
+        {
+            rmvc_pcrm = inl(PCI_RMV_BASE); 
+            printf("rmvc_pcrm is %x\n", rmvc_pcrm);
+            for(i = 0;  i < config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]); i ++)
+            {
+                /* Slot is in byte 2 in _ADR */
+                unsigned char slot = dsdt[config->aml_adr_dword[i] + 2] & 0x1F;
+                /* Sanity check */
+                if (memcmp(dsdt + config->aml_ej0_name[i], "_EJ0", 4)) {
+                    goto oom;
+                }
+                if (!(rmvc_pcrm & (0x1 << slot))) {
+                    memcpy(dsdt + config->aml_ej0_name[i], "EJ0_", 4);
+                }
+            }
+        }
     }
 
+    nr_processor_objects = HVM_MAX_VCPUS;
     /*
      * N.B. ACPI 1.0 operating systems may not handle FADT with revision 2
      * or above properly, notably Windows 2000, which tries to copy FADT
diff --git a/tools/firmware/hvmloader/acpi/dsdt.asl b/tools/firmware/hvmloader/acpi/dsdt.asl
index 247a8ad..1e7695b 100644
--- a/tools/firmware/hvmloader/acpi/dsdt.asl
+++ b/tools/firmware/hvmloader/acpi/dsdt.asl
@@ -16,6 +16,7 @@
  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  * Place - Suite 330, Boston, MA 02111-1307 USA.
  */
+ACPI_EXTRACT_ALL_CODE AmlCode
 
 DefinitionBlock ("DSDT.aml", "DSDT", 2, "Xen", "HVM", 0)
 {
diff --git a/tools/firmware/hvmloader/acpi/mk_dsdt.c b/tools/firmware/hvmloader/acpi/mk_dsdt.c
index 996f30b..4180801 100644
--- a/tools/firmware/hvmloader/acpi/mk_dsdt.c
+++ b/tools/firmware/hvmloader/acpi/mk_dsdt.c
@@ -368,7 +368,9 @@ int main(int argc, char **argv)
         /* hotplug_slot */
         for (slot = 1; slot <= 31; slot++) {
             push_block("Device", "S%i", slot); {
+                printf("ACPI_EXTRACT_NAME_DWORD_CONST aml_adr_dword\n");
                 stmt("Name", "_ADR, %#06x0000", slot);
+                printf("ACPI_EXTRACT_METHOD_STRING aml_ej0_name\n");
                 push_block("Method", "_EJ0,1"); {
                     stmt("Store", "ShiftLeft(1, %#06x), B0EJ", slot);
                     stmt("Return", "0x0");
diff --git a/tools/firmware/hvmloader/mkhex b/tools/firmware/hvmloader/mkhex
old mode 100755
new mode 100644
diff --git a/tools/firmware/hvmloader/ovmf.c b/tools/firmware/hvmloader/ovmf.c
index ee4cbbf..27ff0b5 100644
--- a/tools/firmware/hvmloader/ovmf.c
+++ b/tools/firmware/hvmloader/ovmf.c
@@ -79,7 +79,11 @@ static void ovmf_acpi_build_tables(void)
         .dsdt_anycpu = dsdt_anycpu,
         .dsdt_anycpu_len = dsdt_anycpu_len,
         .dsdt_15cpu = NULL, 
-        .dsdt_15cpu_len = 0
+        .dsdt_15cpu_len = 0,
+        .aml_ej0_name = NULL,
+        .aml_adr_dword = NULL,
+        .aml_ej0_name_len = 0,
+        .aml_adr_dword_len = 0,
     };
 
     acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
diff --git a/tools/firmware/hvmloader/rombios.c b/tools/firmware/hvmloader/rombios.c
index f6f5310..a8b7f95 100644
--- a/tools/firmware/hvmloader/rombios.c
+++ b/tools/firmware/hvmloader/rombios.c
@@ -177,6 +177,10 @@ static void rombios_acpi_build_tables(void)
         .dsdt_anycpu_len = dsdt_anycpu_len,
         .dsdt_15cpu = dsdt_15cpu,
         .dsdt_15cpu_len = dsdt_15cpu_len,
+        .aml_ej0_name = NULL,
+        .aml_adr_dword = NULL,
+        .aml_ej0_name_len = 0,
+        .aml_adr_dword_len = 0,
     };
 
     acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
diff --git a/tools/firmware/hvmloader/seabios.c b/tools/firmware/hvmloader/seabios.c
index f17e67b..8b3a85f 100644
--- a/tools/firmware/hvmloader/seabios.c
+++ b/tools/firmware/hvmloader/seabios.c
@@ -33,6 +33,10 @@
 
 extern unsigned char dsdt_anycpu_qemu_xen[];
 extern int dsdt_anycpu_qemu_xen_len;
+extern unsigned short dsdt_anycpu_qemu_xen_aml_ej0_name[];
+extern unsigned short dsdt_anycpu_qemu_xen_aml_adr_dword[];
+extern int dsdt_anycpu_qemu_xen_aml_ej0_name_len;
+extern int dsdt_anycpu_qemu_xen_aml_adr_dword_len;
 
 struct seabios_info {
     char signature[14]; /* XenHVMSeaBIOS\0 */
@@ -99,6 +103,10 @@ static void seabios_acpi_build_tables(void)
         .dsdt_anycpu_len = dsdt_anycpu_qemu_xen_len,
         .dsdt_15cpu = NULL,
         .dsdt_15cpu_len = 0,
+        .aml_ej0_name = dsdt_anycpu_qemu_xen_aml_ej0_name,
+        .aml_adr_dword = dsdt_anycpu_qemu_xen_aml_adr_dword,
+        .aml_ej0_name_len = dsdt_anycpu_qemu_xen_aml_ej0_name_len,
+        .aml_adr_dword_len = dsdt_anycpu_qemu_xen_aml_adr_dword_len,
     };
 
     acpi_build_tables(&config, rsdp);
diff --git a/tools/firmware/hvmloader/tools/acpi_extract.py b/tools/firmware/hvmloader/tools/acpi_extract.py
new file mode 100644
index 0000000..4fa51f7
--- /dev/null
+++ b/tools/firmware/hvmloader/tools/acpi_extract.py
@@ -0,0 +1,308 @@
+#!/usr/bin/python
+# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+# Process mixed ASL/AML listing (.lst file) produced by iasl -l
+# Locate and execute ACPI_EXTRACT directives, output offset info
+# 
+# Documentation of ACPI_EXTRACT_* directive tags:
+# 
+# These directive tags output offset information from AML for BIOS runtime
+# table generation.
+# Each directive is of the form:
+# ACPI_EXTRACT_<TYPE> <array_name> <Operator> (...)
+# and causes the extractor to create an array
+# named <array_name> with offset, in the generated AML,
+# of an object of a given type in the following <Operator>.
+# 
+# A directive must fit on a single code line.
+# 
+# Object type in AML is verified, a mismatch causes a build failure.
+# 
+# Directives and operators currently supported are:
+# ACPI_EXTRACT_NAME_DWORD_CONST - extract a Dword Const object from Name()
+# ACPI_EXTRACT_NAME_WORD_CONST - extract a Word Const object from Name()
+# ACPI_EXTRACT_NAME_BYTE_CONST - extract a Byte Const object from Name()
+# ACPI_EXTRACT_METHOD_STRING - extract a NameString from Method()
+# ACPI_EXTRACT_NAME_STRING - extract a NameString from Name()
+# ACPI_EXTRACT_PROCESSOR_START - start of Processor() block
+# ACPI_EXTRACT_PROCESSOR_STRING - extract a NameString from Processor()
+# ACPI_EXTRACT_PROCESSOR_END - offset at last byte of Processor() + 1
+# ACPI_EXTRACT_PKG_START - start of Package block
+#
+# ACPI_EXTRACT_ALL_CODE - create an array storing the generated AML bytecode
+# 
+# ACPI_EXTRACT is not allowed anywhere else in code, except in comments.
+
+import re;
+import sys;
+import fileinput;
+
+aml = []
+asl = []
+output = {}
+debug = ""
+
+class asl_line:
+    line = None
+    lineno = None
+    aml_offset = None
+
+def die(diag):
+    sys.stderr.write("Error: %s; %s\n" % (diag, debug))
+    sys.exit(1)
+    
+#Store an ASL command, matching AML offset, and input line (for debugging)
+def add_asl(lineno, line):
+    l = asl_line()
+    l.line = line
+    l.lineno = lineno
+    l.aml_offset = len(aml)
+    asl.append(l)
+
+#Store an AML byte sequence
+#Verify that offset output by iasl matches # of bytes so far
+def add_aml(offset, line):
+    o = int(offset, 16);
+    # Sanity check: offset must match size of code so far
+    if (o != len(aml)):
+        die("Offset 0x%x != 0x%x" % (o, len(aml)))
+    # Strip any trailing dots and ASCII dump after "
+    line = re.sub(r'\s*\.*\s*".*$',"", line)
+    # Strip traling whitespace
+    line = re.sub(r'\s+$',"", line)
+    # Strip leading whitespace
+    line = re.sub(r'^\s+',"", line)
+    # Split on whitespace
+    code = re.split(r'\s+', line)
+    for c in code:
+        # Require a legal hex number, two digits
+        if (not(re.search(r'^[0-9A-Fa-f][0-9A-Fa-f]$', c))):
+            die("Unexpected octet %s" % c);
+        aml.append(int(c, 16));
+
+# Process aml bytecode array, decoding AML
+def aml_pkglen_bytes(offset):
+    # PkgLength can be multibyte. Bits 8-7 give the # of extra bytes.
+    pkglenbytes = aml[offset] >> 6;
+    return pkglenbytes + 1
+
+def aml_pkglen(offset):
+    pkgstart = offset
+    pkglenbytes = aml_pkglen_bytes(offset)
+    pkglen = aml[offset] & 0x3F
+    # If multibyte, first nibble only uses bits 0-3
+    if ((pkglenbytes > 0) and (pkglen & 0x30)):
+        die("PkgLen bytes 0x%x but first nibble 0x%x expected 0x0X" %
+            (pkglen, pkglen))
+    offset += 1
+    pkglenbytes -= 1
+    for i in range(pkglenbytes):
+        pkglen |= aml[offset + i] << (i * 8 + 4)
+    if (len(aml) < pkgstart + pkglen):
+        die("PckgLen 0x%x at offset 0x%x exceeds AML size 0x%x" %
+            (pkglen, offset, len(aml)))
+    return pkglen
+
+# Given method offset, find its NameString offset
+def aml_method_string(offset):
+    #0x14 MethodOp PkgLength NameString MethodFlags TermList
+    if (aml[offset] != 0x14):
+        die( "Method offset 0x%x: expected 0x14 actual 0x%x" %
+             (offset, aml[offset]));
+    offset += 1;
+    pkglenbytes = aml_pkglen_bytes(offset)
+    offset += pkglenbytes;
+    return offset;
+
+# Given name offset, find its NameString offset
+def aml_name_string(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x08):
+        die( "Name offset 0x%x: expected 0x08 actual 0x%x" %
+             (offset, aml[offset]));
+    offset += 1
+    # Block Name Modifier. Skip it.
+    if (aml[offset] == 0x5c or aml[offset] == 0x5e):
+        offset += 1
+    return offset;
+
+# Given data offset, find dword const offset
+def aml_data_dword_const(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x0C):
+        die( "Name offset 0x%x: expected 0x0C actual 0x%x" %
+             (offset, aml[offset]));
+    return offset + 1;
+
+# Given data offset, find word const offset
+def aml_data_word_const(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x0B):
+        die( "Name offset 0x%x: expected 0x0B actual 0x%x" %
+             (offset, aml[offset]));
+    return offset + 1;
+
+# Given data offset, find byte const offset
+def aml_data_byte_const(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x0A):
+        die( "Name offset 0x%x: expected 0x0A actual 0x%x" %
+             (offset, aml[offset]));
+    return offset + 1;
+
+# Given name offset, find dword const offset
+def aml_name_dword_const(offset):
+    return aml_data_dword_const(aml_name_string(offset) + 4)
+
+# Given name offset, find word const offset
+def aml_name_word_const(offset):
+    return aml_data_word_const(aml_name_string(offset) + 4)
+
+# Given name offset, find byte const offset
+def aml_name_byte_const(offset):
+    return aml_data_byte_const(aml_name_string(offset) + 4)
+
+def aml_processor_start(offset):
+    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
+    if ((aml[offset] != 0x5B) or (aml[offset + 1] != 0x83)):
+        die( "Name offset 0x%x: expected 0x5B 0x83 actual 0x%x 0x%x" %
+             (offset, aml[offset], aml[offset + 1]));
+    return offset
+
+def aml_processor_string(offset):
+    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
+    start = aml_processor_start(offset)
+    offset += 2
+    pkglenbytes = aml_pkglen_bytes(offset)
+    offset += pkglenbytes
+    return offset
+
+def aml_processor_end(offset):
+    start = aml_processor_start(offset)
+    offset += 2
+    pkglenbytes = aml_pkglen_bytes(offset)
+    pkglen = aml_pkglen(offset)
+    return offset + pkglen
+
+def aml_package_start(offset):
+    offset = aml_name_string(offset) + 4
+    # 0x12 PkgLength NumElements PackageElementList
+    if (aml[offset] != 0x12):
+        die( "Name offset 0x%x: expected 0x12 actual 0x%x" %
+             (offset, aml[offset]));
+    offset += 1
+    return offset + aml_pkglen_bytes(offset) + 1
+
+lineno = 0
+for line in fileinput.input():
+    # Strip trailing newline
+    line = line.rstrip();
+    # line number and debug string to output in case of errors
+    lineno = lineno + 1
+    debug = "input line %d: %s" % (lineno, line)
+    #ASL listing: space, then line#, then ...., then code
+    pasl = re.compile('^\s+([0-9]+)\.\.\.\.\s*')
+    m = pasl.search(line)
+    if (m):
+        add_asl(lineno, pasl.sub("", line));
+    # AML listing: offset in hex, then ...., then code
+    paml = re.compile('^([0-9A-Fa-f]+)\.\.\.\.\s*')
+    m = paml.search(line)
+    if (m):
+        add_aml(m.group(1), paml.sub("", line))
+
+# Now go over code
+# Track AML offset of a previous non-empty ASL command
+prev_aml_offset = -1
+for i in range(len(asl)):
+    debug = "input line %d: %s" % (asl[i].lineno, asl[i].line)
+
+    l = asl[i].line
+
+    # skip if not an extract directive
+    a = len(re.findall(r'ACPI_EXTRACT', l))
+    if (not a):
+        # If not empty, store AML offset. Will be used for sanity checks
+        # IASL seems to put {}. at random places in the listing.
+        # Ignore any non-words for the purpose of this test.
+        m = re.search(r'\w+', l)
+        if (m):
+                prev_aml_offset = asl[i].aml_offset
+        continue
+
+    if (a > 1):
+        die("Expected at most one ACPI_EXTRACT per line, actual %d" % a)
+
+    mext = re.search(r'''
+                      ^\s* # leading whitespace
+                      /\*\s* # start C comment
+                      (ACPI_EXTRACT_\w+) # directive: group(1)
+                      \s+ # whitspace separates directive from array name
+                      (\w+) # array name: group(2)
+                      \s*\*/ # end of C comment
+                      \s*$ # trailing whitespace
+                      ''', l, re.VERBOSE)
+    if (not mext):
+        die("Stray ACPI_EXTRACT in input")
+
+    # previous command must have produced some AML,
+    # otherwise we are in a middle of a block
+    if (prev_aml_offset == asl[i].aml_offset):
+        die("ACPI_EXTRACT directive in the middle of a block")
+
+    directive = mext.group(1)
+    array = mext.group(2)
+    offset = asl[i].aml_offset
+
+    if (directive == "ACPI_EXTRACT_ALL_CODE"):
+        if array in output:
+            die("%s directive used more than once" % directive)
+        output[array] = aml
+        continue
+    if (directive == "ACPI_EXTRACT_NAME_DWORD_CONST"):
+        offset = aml_name_dword_const(offset)
+    elif (directive == "ACPI_EXTRACT_NAME_WORD_CONST"):
+        offset = aml_name_word_const(offset)
+    elif (directive == "ACPI_EXTRACT_NAME_BYTE_CONST"):
+        offset = aml_name_byte_const(offset)
+    elif (directive == "ACPI_EXTRACT_NAME_STRING"):
+        offset = aml_name_string(offset)
+    elif (directive == "ACPI_EXTRACT_METHOD_STRING"):
+        offset = aml_method_string(offset)
+    elif (directive == "ACPI_EXTRACT_PROCESSOR_START"):
+        offset = aml_processor_start(offset)
+    elif (directive == "ACPI_EXTRACT_PROCESSOR_STRING"):
+        offset = aml_processor_string(offset)
+    elif (directive == "ACPI_EXTRACT_PROCESSOR_END"):
+        offset = aml_processor_end(offset)
+    elif (directive == "ACPI_EXTRACT_PKG_START"):
+        offset = aml_package_start(offset)
+    else:
+        die("Unsupported directive %s" % directive)
+
+    if array not in output:
+        output[array] = []
+    output[array].append(offset)
+
+debug = "at end of file"
+
+def get_value_type(maxvalue):
+    #Use type large enough to fit the table
+    if (maxvalue >= 0x10000):
+            return "int"
+    elif (maxvalue >= 0x100):
+            return "short"
+    else:
+            return "char"
+
+# Pretty print output
+for array in output.keys():
+    otype = get_value_type(max(output[array]))
+    odata = []
+    for value in output[array]:
+        odata.append("0x%x" % value)
+    sys.stdout.write("unsigned %s %s[] = {\n" % (otype, array))
+    sys.stdout.write(",\n".join(odata))
+    sys.stdout.write('\n};\n');
diff --git a/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py b/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py
new file mode 100644
index 0000000..4ae364e
--- /dev/null
+++ b/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py
@@ -0,0 +1,41 @@
+#!/usr/bin/python
+# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+# Read a preprocessed ASL listing and put each ACPI_EXTRACT
+# directive in a comment, to make iasl skip it.
+# We also put each directive on a new line, the machinery
+# in tools/acpi_extract.py requires this.
+
+import re;
+import sys;
+import fileinput;
+
+def die(diag):
+    sys.stderr.write("Error: %s\n" % (diag))
+    sys.exit(1)
+
+# Note: () around pattern make split return matched string as part of list
+psplit = re.compile(r''' (
+                          \b # At word boundary
+                          ACPI_EXTRACT_\w+ # directive
+                          \s+ # some whitespace
+                          \w+ # array name
+                         )''', re.VERBOSE);
+
+lineno = 0
+for line in fileinput.input():
+    # line number and debug string to output in case of errors
+    lineno = lineno + 1
+    debug = "input line %d: %s" % (lineno, line.rstrip())
+
+    s = psplit.split(line);
+    # The way split works, each odd item is the matching ACPI_EXTRACT directive.
+    # Put each in a comment, and on a line by itself.
+    for i in range(len(s)):
+        if (i % 2):
+            sys.stdout.write("\n/* %s */\n" % s[i])
+        else:
+            sys.stdout.write(s[i])
+
-- 
1.8.3.4


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
  2013-10-16 12:03           ` Jan Beulich
  2013-10-22  4:08             ` Gonglei (Arei)
@ 2013-10-22  4:08             ` Gonglei (Arei)
  1 sibling, 0 replies; 38+ messages in thread
From: Gonglei (Arei) @ 2013-10-22  4:08 UTC (permalink / raw)
  To: Jan Beulich, Markus Armbruster
  Cc: Yanqiangjun, Ian Campbell, Hanweidong (Randy),
	Stefano Stabellini, Luonengjun, qemu-devel, xen-devel,
	Fabio Fantoni, anthony.perard, Gaowei (UVP),
	Huangweidong (Hardware)

[-- Attachment #1: Type: text/plain, Size: 28259 bytes --]

Hi, guys. The new patch has been modified based on the principles you suggested, thank you so much.
Last time I test the patch based on the codes of 4.3.0.
This time, I found that the system based on the codes of trunk causes the VM reboot again and again, which I have not found out the reason.
So i can not test the patch based on the codes of trunk (details in EJ0_ACPI_PCI_Hotplug.patch)..
The new patch works well based on the codes of 4.3.0 (details in 4.3.0.patch).

 In Xen platform, after using upstream qemu, the all of pci devices will show hotplug in the windows guest.
 In this situation, the windows guest may occur blue screen when VM' user click the icon of VGA card for trying unplug VGA card.
 However, we don't hope VM's user can do such dangerous operation, and showing all pci devices inside the guest OS is unfriendly.
 This is done by runtime patching:
  - Rename _EJ0 methods for PCI slots in DSDT to EJ0_:note that this has the same checksum, but is ignored by OSPM.
  - At compile time, look for these methods in ASL source, find the matching AML, and store the offsets of these methods in a table named aml_ej0_data.
  - At run time, go over aml_ej0_data, check which slots not support hotplug and patch the ACPI table, replacing _EJ0 with EJ0_.

Signed-off-by: gaowei <gao.gaowei@huawei.com>
Signed-off-by: gonglei <arei.gonglei@huawei.com>
---
 tools/firmware/hvmloader/acpi/Makefile             |  46 ++-
 tools/firmware/hvmloader/acpi/acpi2_0.h            |   5 +
 tools/firmware/hvmloader/acpi/build.c              |  24 +-
 tools/firmware/hvmloader/acpi/dsdt.asl             |   1 +
 tools/firmware/hvmloader/acpi/mk_dsdt.c            |   2 +
 tools/firmware/hvmloader/mkhex                     |   0
 tools/firmware/hvmloader/ovmf.c                    |   6 +-
 tools/firmware/hvmloader/rombios.c                 |   4 +
 tools/firmware/hvmloader/seabios.c                 |   8 +
 tools/firmware/hvmloader/tools/acpi_extract.py     | 308 +++++++++++++++++++++
 .../hvmloader/tools/acpi_extract_preprocess.py     |  41 +++
 11 files changed, 431 insertions(+), 14 deletions(-)
 mode change 100755 => 100644 tools/firmware/hvmloader/mkhex
 create mode 100644 tools/firmware/hvmloader/tools/acpi_extract.py
 create mode 100644 tools/firmware/hvmloader/tools/acpi_extract_preprocess.py

diff --git a/tools/firmware/hvmloader/acpi/Makefile b/tools/firmware/hvmloader/acpi/Makefile
index 2c50851..8b3f7ac 100644
--- a/tools/firmware/hvmloader/acpi/Makefile
+++ b/tools/firmware/hvmloader/acpi/Makefile
@@ -24,30 +24,46 @@ OBJS  = $(patsubst %.c,%.o,$(C_SRC))
 CFLAGS += $(CFLAGS_xeninclude)
 
 vpath iasl $(PATH)
+vpath python $(PATH)
+
+.DELETE_ON_ERROR:$(filter dsdt_%.c,$(C_SRC))
+
 all: acpi.a
 
 ssdt_s3.h ssdt_s4.h ssdt_pm.h ssdt_tpm.h: %.h: %.asl iasl
 	iasl -vs -p $* -tc $<
-	sed -e 's/AmlCode/$*/g' $*.hex >$@
+	sed -e 's/AmlCode/$*/g' $*.hex >$@.tmp
+	$(call move-if-changed,$@.tmp $@)
 	rm -f $*.hex $*.aml
 
 mk_dsdt: mk_dsdt.c
 	$(HOSTCC) $(HOSTCFLAGS) $(CFLAGS_xeninclude) -o $@ mk_dsdt.c
 
 dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
-	awk 'NR > 1 {print s} {s=$$0}' $< > $@
-	./mk_dsdt --dm-version qemu-xen >> $@
-
+	awk 'NR > 1 {print s} {s=$$0}' $< > $@.tmp
+	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@.tmp
+	./mk_dsdt --dm-version qemu-xen >> $@.tmp
+	sed -i 's/aml_ej0_name/dsdt_anycpu_qemu_xen_aml_ej0_name/g' $@.tmp
+	sed -i 's/aml_adr_dword/dsdt_anycpu_qemu_xen_aml_adr_dword/g' $@.tmp
+	$(call move-if-changed,$@.tmp $@)
+	
 # NB. awk invocation is a portable alternative to 'head -n -1'
 dsdt_%cpu.asl: dsdt.asl mk_dsdt
-	awk 'NR > 1 {print s} {s=$$0}' $< > $@
-	./mk_dsdt --maxcpu $*  >> $@
+	awk 'NR > 1 {print s} {s=$$0}' $< > $@.tmp
+	sed -i 's/AmlCode/dsdt_$*cpu/g' $@.tmp
+	./mk_dsdt --maxcpu $*  >> $@.tmp
+	$(call move-if-changed,$@.tmp $@)
 
-$(filter dsdt_%.c,$(C_SRC)): %.c: iasl %.asl
-	iasl -vs -p $* -tc $*.asl
-	sed -e 's/AmlCode/$*/g' $*.hex >$@
-	echo "int $*_len=sizeof($*);" >>$@
-	rm -f $*.aml $*.hex
+$(filter dsdt_%.c,$(C_SRC)): %.c: iasl python %.asl
+	cpp -P $*.asl > $*.asl.i.orig
+	python ../tools/acpi_extract_preprocess.py $*.asl.i.orig > $*.asl.i
+	iasl -vs -l -tc -p $* $*.asl.i
+	python ../tools/acpi_extract.py $*.lst > $@.tmp
+	echo "int $*_len=sizeof($*);" >>$@.tmp
+	if grep -q "$*_aml_ej0_name" $@.tmp; then echo "int $*_aml_ej0_name_len=sizeof($*_aml_ej0_name);" >>$@.tmp; fi
+	if grep -q "$*_aml_adr_dword" $@.tmp; then echo "int $*_aml_adr_dword_len=sizeof($*_aml_adr_dword);" >>$@.tmp;fi
+	$(call move-if-changed,$@.tmp $@)
+	rm -f $*.aml $*.hex $*.asl.i.orig $*.asl.i $*.lst
 
 iasl:
 	@echo
@@ -57,6 +73,12 @@ iasl:
 	@echo 
 	@exit 1
 
+python:
+	@echo
+	@echo "python is needed"
+	@echo
+	@exit 1
+
 build.o: ssdt_s3.h ssdt_s4.h ssdt_pm.h ssdt_tpm.h
 
 acpi.a: $(OBJS)
@@ -64,7 +86,7 @@ acpi.a: $(OBJS)
 
 clean:
 	rm -rf *.a *.o $(IASL_VER) $(IASL_VER).tar.gz $(DEPS)
-	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl
+	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl *.asl.i *.asl.i.orig *.lst *.tmp
 
 install: all
 
diff --git a/tools/firmware/hvmloader/acpi/acpi2_0.h b/tools/firmware/hvmloader/acpi/acpi2_0.h
index 7b22d80..d0c83b8 100644
--- a/tools/firmware/hvmloader/acpi/acpi2_0.h
+++ b/tools/firmware/hvmloader/acpi/acpi2_0.h
@@ -396,6 +396,11 @@ struct acpi_config {
     int dsdt_anycpu_len;
     unsigned char *dsdt_15cpu;
     int dsdt_15cpu_len;
+    unsigned short *aml_ej0_name;
+    unsigned short *aml_adr_dword;
+    int aml_ej0_name_len;
+    int aml_adr_dword_len;
+    
 };
 
 void acpi_build_tables(struct acpi_config *config, unsigned int physical);
diff --git a/tools/firmware/hvmloader/acpi/build.c b/tools/firmware/hvmloader/acpi/build.c
index f1dd3f0..35681aa 100644
--- a/tools/firmware/hvmloader/acpi/build.c
+++ b/tools/firmware/hvmloader/acpi/build.c
@@ -30,6 +30,9 @@
 #define align16(sz)        (((sz) + 15) & ~15)
 #define fixed_strcpy(d, s) strncpy((d), (s), sizeof(d))
 
+
+#define PCI_RMV_BASE 0xae0c
+
 extern struct acpi_20_rsdp Rsdp;
 extern struct acpi_20_rsdt Rsdt;
 extern struct acpi_20_xsdt Xsdt;
@@ -404,6 +407,7 @@ void acpi_build_tables(struct acpi_config *config, unsigned int physical)
     unsigned char       *dsdt;
     unsigned long        secondary_tables[ACPI_MAX_SECONDARY_TABLES];
     int                  nr_secondaries, i;
+    unsigned int rmvc_pcrm = 0;
 
     /* Allocate and initialise the acpi info area. */
     mem_hole_populate_ram(ACPI_INFO_PHYSICAL_ADDRESS >> PAGE_SHIFT, 1);
@@ -438,9 +442,27 @@ void acpi_build_tables(struct acpi_config *config, unsigned int physical)
         dsdt = mem_alloc(config->dsdt_anycpu_len, 16);
         if (!dsdt) goto oom;
         memcpy(dsdt, config->dsdt_anycpu, config->dsdt_anycpu_len);
-        nr_processor_objects = HVM_MAX_VCPUS;
+        if(config->aml_adr_dword_len && config->aml_ej0_name_len &&
+            (config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]) == config->aml_ej0_name_len/sizeof(config->aml_ej0_name[0])))
+        {
+            rmvc_pcrm = inl(PCI_RMV_BASE); 
+            printf("rmvc_pcrm is %x\n", rmvc_pcrm);
+            for(i = 0;  i < config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]); i ++)
+            {
+                /* Slot is in byte 2 in _ADR */
+                unsigned char slot = dsdt[config->aml_adr_dword[i] + 2] & 0x1F;
+                /* Sanity check */
+                if (memcmp(dsdt + config->aml_ej0_name[i], "_EJ0", 4)) {
+                    goto oom;
+                }
+                if (!(rmvc_pcrm & (0x1 << slot))) {
+                    memcpy(dsdt + config->aml_ej0_name[i], "EJ0_", 4);
+                }
+            }
+        }
     }
 
+    nr_processor_objects = HVM_MAX_VCPUS;
     /*
      * N.B. ACPI 1.0 operating systems may not handle FADT with revision 2
      * or above properly, notably Windows 2000, which tries to copy FADT
diff --git a/tools/firmware/hvmloader/acpi/dsdt.asl b/tools/firmware/hvmloader/acpi/dsdt.asl
index 247a8ad..1e7695b 100644
--- a/tools/firmware/hvmloader/acpi/dsdt.asl
+++ b/tools/firmware/hvmloader/acpi/dsdt.asl
@@ -16,6 +16,7 @@
  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  * Place - Suite 330, Boston, MA 02111-1307 USA.
  */
+ACPI_EXTRACT_ALL_CODE AmlCode
 
 DefinitionBlock ("DSDT.aml", "DSDT", 2, "Xen", "HVM", 0)
 {
diff --git a/tools/firmware/hvmloader/acpi/mk_dsdt.c b/tools/firmware/hvmloader/acpi/mk_dsdt.c
index 996f30b..4180801 100644
--- a/tools/firmware/hvmloader/acpi/mk_dsdt.c
+++ b/tools/firmware/hvmloader/acpi/mk_dsdt.c
@@ -368,7 +368,9 @@ int main(int argc, char **argv)
         /* hotplug_slot */
         for (slot = 1; slot <= 31; slot++) {
             push_block("Device", "S%i", slot); {
+                printf("ACPI_EXTRACT_NAME_DWORD_CONST aml_adr_dword\n");
                 stmt("Name", "_ADR, %#06x0000", slot);
+                printf("ACPI_EXTRACT_METHOD_STRING aml_ej0_name\n");
                 push_block("Method", "_EJ0,1"); {
                     stmt("Store", "ShiftLeft(1, %#06x), B0EJ", slot);
                     stmt("Return", "0x0");
diff --git a/tools/firmware/hvmloader/mkhex b/tools/firmware/hvmloader/mkhex
old mode 100755
new mode 100644
diff --git a/tools/firmware/hvmloader/ovmf.c b/tools/firmware/hvmloader/ovmf.c
index ee4cbbf..27ff0b5 100644
--- a/tools/firmware/hvmloader/ovmf.c
+++ b/tools/firmware/hvmloader/ovmf.c
@@ -79,7 +79,11 @@ static void ovmf_acpi_build_tables(void)
         .dsdt_anycpu = dsdt_anycpu,
         .dsdt_anycpu_len = dsdt_anycpu_len,
         .dsdt_15cpu = NULL, 
-        .dsdt_15cpu_len = 0
+        .dsdt_15cpu_len = 0,
+        .aml_ej0_name = NULL,
+        .aml_adr_dword = NULL,
+        .aml_ej0_name_len = 0,
+        .aml_adr_dword_len = 0,
     };
 
     acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
diff --git a/tools/firmware/hvmloader/rombios.c b/tools/firmware/hvmloader/rombios.c
index 810bd24..803c9fa 100644
--- a/tools/firmware/hvmloader/rombios.c
+++ b/tools/firmware/hvmloader/rombios.c
@@ -179,6 +179,10 @@ static void rombios_acpi_build_tables(void)
         .dsdt_anycpu_len = dsdt_anycpu_len,
         .dsdt_15cpu = dsdt_15cpu,
         .dsdt_15cpu_len = dsdt_15cpu_len,
+        .aml_ej0_name = NULL,
+        .aml_adr_dword = NULL,
+        .aml_ej0_name_len = 0,
+        .aml_adr_dword_len = 0,
     };
 
     acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
diff --git a/tools/firmware/hvmloader/seabios.c b/tools/firmware/hvmloader/seabios.c
index dd7dfbe..ca01d27 100644
--- a/tools/firmware/hvmloader/seabios.c
+++ b/tools/firmware/hvmloader/seabios.c
@@ -33,6 +33,10 @@
 
 extern unsigned char dsdt_anycpu_qemu_xen[];
 extern int dsdt_anycpu_qemu_xen_len;
+extern unsigned short dsdt_anycpu_qemu_xen_aml_ej0_name[];
+extern unsigned short dsdt_anycpu_qemu_xen_aml_adr_dword[];
+extern int dsdt_anycpu_qemu_xen_aml_ej0_name_len;
+extern int dsdt_anycpu_qemu_xen_aml_adr_dword_len;
 
 struct seabios_info {
     char signature[14]; /* XenHVMSeaBIOS\0 */
@@ -99,6 +103,10 @@ static void seabios_acpi_build_tables(void)
         .dsdt_anycpu_len = dsdt_anycpu_qemu_xen_len,
         .dsdt_15cpu = NULL,
         .dsdt_15cpu_len = 0,
+        .aml_ej0_name = dsdt_anycpu_qemu_xen_aml_ej0_name,
+        .aml_adr_dword = dsdt_anycpu_qemu_xen_aml_adr_dword,
+        .aml_ej0_name_len = dsdt_anycpu_qemu_xen_aml_ej0_name_len,
+        .aml_adr_dword_len = dsdt_anycpu_qemu_xen_aml_adr_dword_len,
     };
 
     acpi_build_tables(&config, rsdp);
diff --git a/tools/firmware/hvmloader/tools/acpi_extract.py b/tools/firmware/hvmloader/tools/acpi_extract.py
new file mode 100644
index 0000000..4fa51f7
--- /dev/null
+++ b/tools/firmware/hvmloader/tools/acpi_extract.py
@@ -0,0 +1,308 @@
+#!/usr/bin/python
+# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+# Process mixed ASL/AML listing (.lst file) produced by iasl -l
+# Locate and execute ACPI_EXTRACT directives, output offset info
+# 
+# Documentation of ACPI_EXTRACT_* directive tags:
+# 
+# These directive tags output offset information from AML for BIOS runtime
+# table generation.
+# Each directive is of the form:
+# ACPI_EXTRACT_<TYPE> <array_name> <Operator> (...)
+# and causes the extractor to create an array
+# named <array_name> with offset, in the generated AML,
+# of an object of a given type in the following <Operator>.
+# 
+# A directive must fit on a single code line.
+# 
+# Object type in AML is verified, a mismatch causes a build failure.
+# 
+# Directives and operators currently supported are:
+# ACPI_EXTRACT_NAME_DWORD_CONST - extract a Dword Const object from Name()
+# ACPI_EXTRACT_NAME_WORD_CONST - extract a Word Const object from Name()
+# ACPI_EXTRACT_NAME_BYTE_CONST - extract a Byte Const object from Name()
+# ACPI_EXTRACT_METHOD_STRING - extract a NameString from Method()
+# ACPI_EXTRACT_NAME_STRING - extract a NameString from Name()
+# ACPI_EXTRACT_PROCESSOR_START - start of Processor() block
+# ACPI_EXTRACT_PROCESSOR_STRING - extract a NameString from Processor()
+# ACPI_EXTRACT_PROCESSOR_END - offset at last byte of Processor() + 1
+# ACPI_EXTRACT_PKG_START - start of Package block
+#
+# ACPI_EXTRACT_ALL_CODE - create an array storing the generated AML bytecode
+# 
+# ACPI_EXTRACT is not allowed anywhere else in code, except in comments.
+
+import re;
+import sys;
+import fileinput;
+
+aml = []
+asl = []
+output = {}
+debug = ""
+
+class asl_line:
+    line = None
+    lineno = None
+    aml_offset = None
+
+def die(diag):
+    sys.stderr.write("Error: %s; %s\n" % (diag, debug))
+    sys.exit(1)
+    
+#Store an ASL command, matching AML offset, and input line (for debugging)
+def add_asl(lineno, line):
+    l = asl_line()
+    l.line = line
+    l.lineno = lineno
+    l.aml_offset = len(aml)
+    asl.append(l)
+
+#Store an AML byte sequence
+#Verify that offset output by iasl matches # of bytes so far
+def add_aml(offset, line):
+    o = int(offset, 16);
+    # Sanity check: offset must match size of code so far
+    if (o != len(aml)):
+        die("Offset 0x%x != 0x%x" % (o, len(aml)))
+    # Strip any trailing dots and ASCII dump after "
+    line = re.sub(r'\s*\.*\s*".*$',"", line)
+    # Strip traling whitespace
+    line = re.sub(r'\s+$',"", line)
+    # Strip leading whitespace
+    line = re.sub(r'^\s+',"", line)
+    # Split on whitespace
+    code = re.split(r'\s+', line)
+    for c in code:
+        # Require a legal hex number, two digits
+        if (not(re.search(r'^[0-9A-Fa-f][0-9A-Fa-f]$', c))):
+            die("Unexpected octet %s" % c);
+        aml.append(int(c, 16));
+
+# Process aml bytecode array, decoding AML
+def aml_pkglen_bytes(offset):
+    # PkgLength can be multibyte. Bits 8-7 give the # of extra bytes.
+    pkglenbytes = aml[offset] >> 6;
+    return pkglenbytes + 1
+
+def aml_pkglen(offset):
+    pkgstart = offset
+    pkglenbytes = aml_pkglen_bytes(offset)
+    pkglen = aml[offset] & 0x3F
+    # If multibyte, first nibble only uses bits 0-3
+    if ((pkglenbytes > 0) and (pkglen & 0x30)):
+        die("PkgLen bytes 0x%x but first nibble 0x%x expected 0x0X" %
+            (pkglen, pkglen))
+    offset += 1
+    pkglenbytes -= 1
+    for i in range(pkglenbytes):
+        pkglen |= aml[offset + i] << (i * 8 + 4)
+    if (len(aml) < pkgstart + pkglen):
+        die("PckgLen 0x%x at offset 0x%x exceeds AML size 0x%x" %
+            (pkglen, offset, len(aml)))
+    return pkglen
+
+# Given method offset, find its NameString offset
+def aml_method_string(offset):
+    #0x14 MethodOp PkgLength NameString MethodFlags TermList
+    if (aml[offset] != 0x14):
+        die( "Method offset 0x%x: expected 0x14 actual 0x%x" %
+             (offset, aml[offset]));
+    offset += 1;
+    pkglenbytes = aml_pkglen_bytes(offset)
+    offset += pkglenbytes;
+    return offset;
+
+# Given name offset, find its NameString offset
+def aml_name_string(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x08):
+        die( "Name offset 0x%x: expected 0x08 actual 0x%x" %
+             (offset, aml[offset]));
+    offset += 1
+    # Block Name Modifier. Skip it.
+    if (aml[offset] == 0x5c or aml[offset] == 0x5e):
+        offset += 1
+    return offset;
+
+# Given data offset, find dword const offset
+def aml_data_dword_const(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x0C):
+        die( "Name offset 0x%x: expected 0x0C actual 0x%x" %
+             (offset, aml[offset]));
+    return offset + 1;
+
+# Given data offset, find word const offset
+def aml_data_word_const(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x0B):
+        die( "Name offset 0x%x: expected 0x0B actual 0x%x" %
+             (offset, aml[offset]));
+    return offset + 1;
+
+# Given data offset, find byte const offset
+def aml_data_byte_const(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x0A):
+        die( "Name offset 0x%x: expected 0x0A actual 0x%x" %
+             (offset, aml[offset]));
+    return offset + 1;
+
+# Given name offset, find dword const offset
+def aml_name_dword_const(offset):
+    return aml_data_dword_const(aml_name_string(offset) + 4)
+
+# Given name offset, find word const offset
+def aml_name_word_const(offset):
+    return aml_data_word_const(aml_name_string(offset) + 4)
+
+# Given name offset, find byte const offset
+def aml_name_byte_const(offset):
+    return aml_data_byte_const(aml_name_string(offset) + 4)
+
+def aml_processor_start(offset):
+    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
+    if ((aml[offset] != 0x5B) or (aml[offset + 1] != 0x83)):
+        die( "Name offset 0x%x: expected 0x5B 0x83 actual 0x%x 0x%x" %
+             (offset, aml[offset], aml[offset + 1]));
+    return offset
+
+def aml_processor_string(offset):
+    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
+    start = aml_processor_start(offset)
+    offset += 2
+    pkglenbytes = aml_pkglen_bytes(offset)
+    offset += pkglenbytes
+    return offset
+
+def aml_processor_end(offset):
+    start = aml_processor_start(offset)
+    offset += 2
+    pkglenbytes = aml_pkglen_bytes(offset)
+    pkglen = aml_pkglen(offset)
+    return offset + pkglen
+
+def aml_package_start(offset):
+    offset = aml_name_string(offset) + 4
+    # 0x12 PkgLength NumElements PackageElementList
+    if (aml[offset] != 0x12):
+        die( "Name offset 0x%x: expected 0x12 actual 0x%x" %
+             (offset, aml[offset]));
+    offset += 1
+    return offset + aml_pkglen_bytes(offset) + 1
+
+lineno = 0
+for line in fileinput.input():
+    # Strip trailing newline
+    line = line.rstrip();
+    # line number and debug string to output in case of errors
+    lineno = lineno + 1
+    debug = "input line %d: %s" % (lineno, line)
+    #ASL listing: space, then line#, then ...., then code
+    pasl = re.compile('^\s+([0-9]+)\.\.\.\.\s*')
+    m = pasl.search(line)
+    if (m):
+        add_asl(lineno, pasl.sub("", line));
+    # AML listing: offset in hex, then ...., then code
+    paml = re.compile('^([0-9A-Fa-f]+)\.\.\.\.\s*')
+    m = paml.search(line)
+    if (m):
+        add_aml(m.group(1), paml.sub("", line))
+
+# Now go over code
+# Track AML offset of a previous non-empty ASL command
+prev_aml_offset = -1
+for i in range(len(asl)):
+    debug = "input line %d: %s" % (asl[i].lineno, asl[i].line)
+
+    l = asl[i].line
+
+    # skip if not an extract directive
+    a = len(re.findall(r'ACPI_EXTRACT', l))
+    if (not a):
+        # If not empty, store AML offset. Will be used for sanity checks
+        # IASL seems to put {}. at random places in the listing.
+        # Ignore any non-words for the purpose of this test.
+        m = re.search(r'\w+', l)
+        if (m):
+                prev_aml_offset = asl[i].aml_offset
+        continue
+
+    if (a > 1):
+        die("Expected at most one ACPI_EXTRACT per line, actual %d" % a)
+
+    mext = re.search(r'''
+                      ^\s* # leading whitespace
+                      /\*\s* # start C comment
+                      (ACPI_EXTRACT_\w+) # directive: group(1)
+                      \s+ # whitspace separates directive from array name
+                      (\w+) # array name: group(2)
+                      \s*\*/ # end of C comment
+                      \s*$ # trailing whitespace
+                      ''', l, re.VERBOSE)
+    if (not mext):
+        die("Stray ACPI_EXTRACT in input")
+
+    # previous command must have produced some AML,
+    # otherwise we are in a middle of a block
+    if (prev_aml_offset == asl[i].aml_offset):
+        die("ACPI_EXTRACT directive in the middle of a block")
+
+    directive = mext.group(1)
+    array = mext.group(2)
+    offset = asl[i].aml_offset
+
+    if (directive == "ACPI_EXTRACT_ALL_CODE"):
+        if array in output:
+            die("%s directive used more than once" % directive)
+        output[array] = aml
+        continue
+    if (directive == "ACPI_EXTRACT_NAME_DWORD_CONST"):
+        offset = aml_name_dword_const(offset)
+    elif (directive == "ACPI_EXTRACT_NAME_WORD_CONST"):
+        offset = aml_name_word_const(offset)
+    elif (directive == "ACPI_EXTRACT_NAME_BYTE_CONST"):
+        offset = aml_name_byte_const(offset)
+    elif (directive == "ACPI_EXTRACT_NAME_STRING"):
+        offset = aml_name_string(offset)
+    elif (directive == "ACPI_EXTRACT_METHOD_STRING"):
+        offset = aml_method_string(offset)
+    elif (directive == "ACPI_EXTRACT_PROCESSOR_START"):
+        offset = aml_processor_start(offset)
+    elif (directive == "ACPI_EXTRACT_PROCESSOR_STRING"):
+        offset = aml_processor_string(offset)
+    elif (directive == "ACPI_EXTRACT_PROCESSOR_END"):
+        offset = aml_processor_end(offset)
+    elif (directive == "ACPI_EXTRACT_PKG_START"):
+        offset = aml_package_start(offset)
+    else:
+        die("Unsupported directive %s" % directive)
+
+    if array not in output:
+        output[array] = []
+    output[array].append(offset)
+
+debug = "at end of file"
+
+def get_value_type(maxvalue):
+    #Use type large enough to fit the table
+    if (maxvalue >= 0x10000):
+            return "int"
+    elif (maxvalue >= 0x100):
+            return "short"
+    else:
+            return "char"
+
+# Pretty print output
+for array in output.keys():
+    otype = get_value_type(max(output[array]))
+    odata = []
+    for value in output[array]:
+        odata.append("0x%x" % value)
+    sys.stdout.write("unsigned %s %s[] = {\n" % (otype, array))
+    sys.stdout.write(",\n".join(odata))
+    sys.stdout.write('\n};\n');
diff --git a/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py b/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py
new file mode 100644
index 0000000..4ae364e
--- /dev/null
+++ b/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py
@@ -0,0 +1,41 @@
+#!/usr/bin/python
+# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+# Read a preprocessed ASL listing and put each ACPI_EXTRACT
+# directive in a comment, to make iasl skip it.
+# We also put each directive on a new line, the machinery
+# in tools/acpi_extract.py requires this.
+
+import re;
+import sys;
+import fileinput;
+
+def die(diag):
+    sys.stderr.write("Error: %s\n" % (diag))
+    sys.exit(1)
+
+# Note: () around pattern make split return matched string as part of list
+psplit = re.compile(r''' (
+                          \b # At word boundary
+                          ACPI_EXTRACT_\w+ # directive
+                          \s+ # some whitespace
+                          \w+ # array name
+                         )''', re.VERBOSE);
+
+lineno = 0
+for line in fileinput.input():
+    # line number and debug string to output in case of errors
+    lineno = lineno + 1
+    debug = "input line %d: %s" % (lineno, line.rstrip())
+
+    s = psplit.split(line);
+    # The way split works, each odd item is the matching ACPI_EXTRACT directive.
+    # Put each in a comment, and on a line by itself.
+    for i in range(len(s)):
+        if (i % 2):
+            sys.stdout.write("\n/* %s */\n" % s[i])
+        else:
+            sys.stdout.write(s[i])
+
-- 
1.8.3.4

Best regards,
-Gonglei

> -----Original Message-----
> From: Jan Beulich [mailto:JBeulich@suse.com]
> Sent: Wednesday, October 16, 2013 8:04 PM
> To: Markus Armbruster
> Cc: anthony.perard@citrix.com; Ian Campbell; Stefano Stabellini; Gonglei (Arei);
> Gaowei (UVP); Hanweidong (Randy); Huangweidong (Hardware); Luonengjun;
> Yanqiangjun; xen-devel@lists.xen.org; Fabio Fantoni; qemu-devel@nongnu.org
> Subject: Re: [Qemu-devel] [Xen-devel] Hvmloader: Modify ACPI to only supply
> _EJ0 methods for PCIslots that support hotplug by runtime patching
> 
> >>> On 16.10.13 at 13:10, Markus Armbruster <armbru@redhat.com> wrote:
> > Ian Campbell <Ian.Campbell@citrix.com> writes:
> >
> >> On Wed, 2013-10-16 at 12:49 +0200, Markus Armbruster wrote:
> >>> Ian Campbell <Ian.Campbell@citrix.com> writes:
> >>>
> >>> > On Wed, 2013-10-16 at 10:54 +0100, Jan Beulich wrote:
> >>> >> >>> On 16.10.13 at 08:30, "Gonglei (Arei)" <arei.gonglei@huawei.com>
> wrote:
> >>> >> > --- hvmloader/acpi/Makefile	2013-10-16 11:51:53.000000000 +0800
> >>> >> > +++ hvmloader_new//acpi/Makefile	2013-10-16
> 11:51:58.000000000 +0800
> >>> >> > @@ -36,18 +36,34 @@
> >>> >> >
> >>> >> >  dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
> >>> >> >  	awk 'NR > 1 {print s} {s=$$0}' $< > $@
> >>> >> > -	./mk_dsdt --dm-version qemu-xen >> $@
> >>> >> > +	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@
> >>> >>
> >>> >> This must never be done - if someone hits Ctrl-C in the middle of
> >>> >> this, you'll have a modified but incomplete generated file. You
> >>> >> either need to use properly chained rules, or do all output to a
> >>> >> temporary file which you rename as the last step.
> >>> >>
> >>> >> I realize that the problem existed before your change, but you
> >>> >> making it worse requires doing it properly now.
> >>> >
> >>> > The correct way to do this is to generate to a temporary file and then
> >>> > use $(call move-if-changed,$@.tmp,$@). There are a bunch of examples
> in
> >>> > tools/libxl/Makefile and elsewhere.
> >>>
> >>> Quoting the GNU make manual[*]:
> >>>
> >>>     So generally the right thing to do is to delete the target file if
> >>>     the recipe fails after beginning to change the file.  make will do
> >>>     this if .DELETE_ON_ERROR appears as a target.  This is almost
> always
> >>>     what you want make to do, but it is not historical practice; so for
> >>>     compatibility, you must explicitly request it.
> >>>
> >>> In my opinion, every Makefile should request it.
> >>>
> >>> [*] https://www.gnu.org/software/make/manual/html_node/Errors.html
> >>
> >> I think this is somewhat orthogonal to the use of move-if-changed which
> >> is there to ensure that the timestamp doesn't change gratuitously and
> >> cause a load of knock on rebuilds even though the regenerated content is
> >> identical.
> >
> > Yes.  I was latching onto the "if someone hits Ctrl-C in the middle of
> > this, you'll have a modified but incomplete generated file" phrase.
> 
> Right, but Ctrl-C is only the soft way of failing. If the system
> happens to crash at the right moment, make won't be able to go
> and delete the file anymore. IOW the move-if-changed approach
> covers a wider range of situations _and_ had the benefit of
> avoiding unnecessary rebuilds.
> 
> Jan


[-- Attachment #2: EJ0_ACPI_PCI_Hotplug.patch --]
[-- Type: application/octet-stream, Size: 24071 bytes --]

From 02625056146e443ba3092dcca6cf27c775f2e621 Mon Sep 17 00:00:00 2001
From: gaowei <gao.gaowei@huawei.com>
Date: Tue, 22 Oct 2013 11:42:53 +0800
Subject: [PATCH] Hvmloader: Modify ACPI to only supply _EJ0 methods for
 PCIslots that support hotplug by runtime patching

 In Xen platform, after using upstream qemu, the all of pci devices will show hotplug in the windows guest.
 In this situation, the windows guest may occur blue screen when VM' user click the icon of VGA card for trying unplug VGA card.
 However, we don't hope VM's user can do such dangerous operation, and showing all pci devices inside the guest OS is unfriendly.
 This is done by runtime patching:
  - Rename _EJ0 methods for PCI slots in DSDT to EJ0_:note that this has the same checksum, but is ignored by OSPM.
  - At compile time, look for these methods in ASL source,find the matching AML, and store the offsets of these methods in a table named aml_ej0_data.
  - At run time, go over aml_ej0_data, check which slots not support hotplug and patch the ACPI table, replacing _EJ0 with EJ0_.

Signed-off-by: gaowei <gao.gaowei@huawei.com>
Signed-off-by: gonglei <arei.gonglei@huawei.com>
---
 tools/firmware/hvmloader/acpi/Makefile             |  46 ++-
 tools/firmware/hvmloader/acpi/acpi2_0.h            |   5 +
 tools/firmware/hvmloader/acpi/build.c              |  24 +-
 tools/firmware/hvmloader/acpi/dsdt.asl             |   1 +
 tools/firmware/hvmloader/acpi/mk_dsdt.c            |   2 +
 tools/firmware/hvmloader/mkhex                     |   0
 tools/firmware/hvmloader/ovmf.c                    |   6 +-
 tools/firmware/hvmloader/rombios.c                 |   4 +
 tools/firmware/hvmloader/seabios.c                 |   8 +
 tools/firmware/hvmloader/tools/acpi_extract.py     | 308 +++++++++++++++++++++
 .../hvmloader/tools/acpi_extract_preprocess.py     |  41 +++
 11 files changed, 431 insertions(+), 14 deletions(-)
 mode change 100755 => 100644 tools/firmware/hvmloader/mkhex
 create mode 100644 tools/firmware/hvmloader/tools/acpi_extract.py
 create mode 100644 tools/firmware/hvmloader/tools/acpi_extract_preprocess.py

diff --git a/tools/firmware/hvmloader/acpi/Makefile b/tools/firmware/hvmloader/acpi/Makefile
index 2c50851..8b3f7ac 100644
--- a/tools/firmware/hvmloader/acpi/Makefile
+++ b/tools/firmware/hvmloader/acpi/Makefile
@@ -24,30 +24,46 @@ OBJS  = $(patsubst %.c,%.o,$(C_SRC))
 CFLAGS += $(CFLAGS_xeninclude)
 
 vpath iasl $(PATH)
+vpath python $(PATH)
+
+.DELETE_ON_ERROR:$(filter dsdt_%.c,$(C_SRC))
+
 all: acpi.a
 
 ssdt_s3.h ssdt_s4.h ssdt_pm.h ssdt_tpm.h: %.h: %.asl iasl
 	iasl -vs -p $* -tc $<
-	sed -e 's/AmlCode/$*/g' $*.hex >$@
+	sed -e 's/AmlCode/$*/g' $*.hex >$@.tmp
+	$(call move-if-changed,$@.tmp $@)
 	rm -f $*.hex $*.aml
 
 mk_dsdt: mk_dsdt.c
 	$(HOSTCC) $(HOSTCFLAGS) $(CFLAGS_xeninclude) -o $@ mk_dsdt.c
 
 dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
-	awk 'NR > 1 {print s} {s=$$0}' $< > $@
-	./mk_dsdt --dm-version qemu-xen >> $@
-
+	awk 'NR > 1 {print s} {s=$$0}' $< > $@.tmp
+	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@.tmp
+	./mk_dsdt --dm-version qemu-xen >> $@.tmp
+	sed -i 's/aml_ej0_name/dsdt_anycpu_qemu_xen_aml_ej0_name/g' $@.tmp
+	sed -i 's/aml_adr_dword/dsdt_anycpu_qemu_xen_aml_adr_dword/g' $@.tmp
+	$(call move-if-changed,$@.tmp $@)
+	
 # NB. awk invocation is a portable alternative to 'head -n -1'
 dsdt_%cpu.asl: dsdt.asl mk_dsdt
-	awk 'NR > 1 {print s} {s=$$0}' $< > $@
-	./mk_dsdt --maxcpu $*  >> $@
+	awk 'NR > 1 {print s} {s=$$0}' $< > $@.tmp
+	sed -i 's/AmlCode/dsdt_$*cpu/g' $@.tmp
+	./mk_dsdt --maxcpu $*  >> $@.tmp
+	$(call move-if-changed,$@.tmp $@)
 
-$(filter dsdt_%.c,$(C_SRC)): %.c: iasl %.asl
-	iasl -vs -p $* -tc $*.asl
-	sed -e 's/AmlCode/$*/g' $*.hex >$@
-	echo "int $*_len=sizeof($*);" >>$@
-	rm -f $*.aml $*.hex
+$(filter dsdt_%.c,$(C_SRC)): %.c: iasl python %.asl
+	cpp -P $*.asl > $*.asl.i.orig
+	python ../tools/acpi_extract_preprocess.py $*.asl.i.orig > $*.asl.i
+	iasl -vs -l -tc -p $* $*.asl.i
+	python ../tools/acpi_extract.py $*.lst > $@.tmp
+	echo "int $*_len=sizeof($*);" >>$@.tmp
+	if grep -q "$*_aml_ej0_name" $@.tmp; then echo "int $*_aml_ej0_name_len=sizeof($*_aml_ej0_name);" >>$@.tmp; fi
+	if grep -q "$*_aml_adr_dword" $@.tmp; then echo "int $*_aml_adr_dword_len=sizeof($*_aml_adr_dword);" >>$@.tmp;fi
+	$(call move-if-changed,$@.tmp $@)
+	rm -f $*.aml $*.hex $*.asl.i.orig $*.asl.i $*.lst
 
 iasl:
 	@echo
@@ -57,6 +73,12 @@ iasl:
 	@echo 
 	@exit 1
 
+python:
+	@echo
+	@echo "python is needed"
+	@echo
+	@exit 1
+
 build.o: ssdt_s3.h ssdt_s4.h ssdt_pm.h ssdt_tpm.h
 
 acpi.a: $(OBJS)
@@ -64,7 +86,7 @@ acpi.a: $(OBJS)
 
 clean:
 	rm -rf *.a *.o $(IASL_VER) $(IASL_VER).tar.gz $(DEPS)
-	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl
+	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl *.asl.i *.asl.i.orig *.lst *.tmp
 
 install: all
 
diff --git a/tools/firmware/hvmloader/acpi/acpi2_0.h b/tools/firmware/hvmloader/acpi/acpi2_0.h
index 7b22d80..d0c83b8 100644
--- a/tools/firmware/hvmloader/acpi/acpi2_0.h
+++ b/tools/firmware/hvmloader/acpi/acpi2_0.h
@@ -396,6 +396,11 @@ struct acpi_config {
     int dsdt_anycpu_len;
     unsigned char *dsdt_15cpu;
     int dsdt_15cpu_len;
+    unsigned short *aml_ej0_name;
+    unsigned short *aml_adr_dword;
+    int aml_ej0_name_len;
+    int aml_adr_dword_len;
+    
 };
 
 void acpi_build_tables(struct acpi_config *config, unsigned int physical);
diff --git a/tools/firmware/hvmloader/acpi/build.c b/tools/firmware/hvmloader/acpi/build.c
index f1dd3f0..35681aa 100644
--- a/tools/firmware/hvmloader/acpi/build.c
+++ b/tools/firmware/hvmloader/acpi/build.c
@@ -30,6 +30,9 @@
 #define align16(sz)        (((sz) + 15) & ~15)
 #define fixed_strcpy(d, s) strncpy((d), (s), sizeof(d))
 
+
+#define PCI_RMV_BASE 0xae0c
+
 extern struct acpi_20_rsdp Rsdp;
 extern struct acpi_20_rsdt Rsdt;
 extern struct acpi_20_xsdt Xsdt;
@@ -404,6 +407,7 @@ void acpi_build_tables(struct acpi_config *config, unsigned int physical)
     unsigned char       *dsdt;
     unsigned long        secondary_tables[ACPI_MAX_SECONDARY_TABLES];
     int                  nr_secondaries, i;
+    unsigned int rmvc_pcrm = 0;
 
     /* Allocate and initialise the acpi info area. */
     mem_hole_populate_ram(ACPI_INFO_PHYSICAL_ADDRESS >> PAGE_SHIFT, 1);
@@ -438,9 +442,27 @@ void acpi_build_tables(struct acpi_config *config, unsigned int physical)
         dsdt = mem_alloc(config->dsdt_anycpu_len, 16);
         if (!dsdt) goto oom;
         memcpy(dsdt, config->dsdt_anycpu, config->dsdt_anycpu_len);
-        nr_processor_objects = HVM_MAX_VCPUS;
+        if(config->aml_adr_dword_len && config->aml_ej0_name_len &&
+            (config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]) == config->aml_ej0_name_len/sizeof(config->aml_ej0_name[0])))
+        {
+            rmvc_pcrm = inl(PCI_RMV_BASE); 
+            printf("rmvc_pcrm is %x\n", rmvc_pcrm);
+            for(i = 0;  i < config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]); i ++)
+            {
+                /* Slot is in byte 2 in _ADR */
+                unsigned char slot = dsdt[config->aml_adr_dword[i] + 2] & 0x1F;
+                /* Sanity check */
+                if (memcmp(dsdt + config->aml_ej0_name[i], "_EJ0", 4)) {
+                    goto oom;
+                }
+                if (!(rmvc_pcrm & (0x1 << slot))) {
+                    memcpy(dsdt + config->aml_ej0_name[i], "EJ0_", 4);
+                }
+            }
+        }
     }
 
+    nr_processor_objects = HVM_MAX_VCPUS;
     /*
      * N.B. ACPI 1.0 operating systems may not handle FADT with revision 2
      * or above properly, notably Windows 2000, which tries to copy FADT
diff --git a/tools/firmware/hvmloader/acpi/dsdt.asl b/tools/firmware/hvmloader/acpi/dsdt.asl
index 247a8ad..1e7695b 100644
--- a/tools/firmware/hvmloader/acpi/dsdt.asl
+++ b/tools/firmware/hvmloader/acpi/dsdt.asl
@@ -16,6 +16,7 @@
  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  * Place - Suite 330, Boston, MA 02111-1307 USA.
  */
+ACPI_EXTRACT_ALL_CODE AmlCode
 
 DefinitionBlock ("DSDT.aml", "DSDT", 2, "Xen", "HVM", 0)
 {
diff --git a/tools/firmware/hvmloader/acpi/mk_dsdt.c b/tools/firmware/hvmloader/acpi/mk_dsdt.c
index 996f30b..4180801 100644
--- a/tools/firmware/hvmloader/acpi/mk_dsdt.c
+++ b/tools/firmware/hvmloader/acpi/mk_dsdt.c
@@ -368,7 +368,9 @@ int main(int argc, char **argv)
         /* hotplug_slot */
         for (slot = 1; slot <= 31; slot++) {
             push_block("Device", "S%i", slot); {
+                printf("ACPI_EXTRACT_NAME_DWORD_CONST aml_adr_dword\n");
                 stmt("Name", "_ADR, %#06x0000", slot);
+                printf("ACPI_EXTRACT_METHOD_STRING aml_ej0_name\n");
                 push_block("Method", "_EJ0,1"); {
                     stmt("Store", "ShiftLeft(1, %#06x), B0EJ", slot);
                     stmt("Return", "0x0");
diff --git a/tools/firmware/hvmloader/mkhex b/tools/firmware/hvmloader/mkhex
old mode 100755
new mode 100644
diff --git a/tools/firmware/hvmloader/ovmf.c b/tools/firmware/hvmloader/ovmf.c
index ee4cbbf..27ff0b5 100644
--- a/tools/firmware/hvmloader/ovmf.c
+++ b/tools/firmware/hvmloader/ovmf.c
@@ -79,7 +79,11 @@ static void ovmf_acpi_build_tables(void)
         .dsdt_anycpu = dsdt_anycpu,
         .dsdt_anycpu_len = dsdt_anycpu_len,
         .dsdt_15cpu = NULL, 
-        .dsdt_15cpu_len = 0
+        .dsdt_15cpu_len = 0,
+        .aml_ej0_name = NULL,
+        .aml_adr_dword = NULL,
+        .aml_ej0_name_len = 0,
+        .aml_adr_dword_len = 0,
     };
 
     acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
diff --git a/tools/firmware/hvmloader/rombios.c b/tools/firmware/hvmloader/rombios.c
index 810bd24..803c9fa 100644
--- a/tools/firmware/hvmloader/rombios.c
+++ b/tools/firmware/hvmloader/rombios.c
@@ -179,6 +179,10 @@ static void rombios_acpi_build_tables(void)
         .dsdt_anycpu_len = dsdt_anycpu_len,
         .dsdt_15cpu = dsdt_15cpu,
         .dsdt_15cpu_len = dsdt_15cpu_len,
+        .aml_ej0_name = NULL,
+        .aml_adr_dword = NULL,
+        .aml_ej0_name_len = 0,
+        .aml_adr_dword_len = 0,
     };
 
     acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
diff --git a/tools/firmware/hvmloader/seabios.c b/tools/firmware/hvmloader/seabios.c
index dd7dfbe..ca01d27 100644
--- a/tools/firmware/hvmloader/seabios.c
+++ b/tools/firmware/hvmloader/seabios.c
@@ -33,6 +33,10 @@
 
 extern unsigned char dsdt_anycpu_qemu_xen[];
 extern int dsdt_anycpu_qemu_xen_len;
+extern unsigned short dsdt_anycpu_qemu_xen_aml_ej0_name[];
+extern unsigned short dsdt_anycpu_qemu_xen_aml_adr_dword[];
+extern int dsdt_anycpu_qemu_xen_aml_ej0_name_len;
+extern int dsdt_anycpu_qemu_xen_aml_adr_dword_len;
 
 struct seabios_info {
     char signature[14]; /* XenHVMSeaBIOS\0 */
@@ -99,6 +103,10 @@ static void seabios_acpi_build_tables(void)
         .dsdt_anycpu_len = dsdt_anycpu_qemu_xen_len,
         .dsdt_15cpu = NULL,
         .dsdt_15cpu_len = 0,
+        .aml_ej0_name = dsdt_anycpu_qemu_xen_aml_ej0_name,
+        .aml_adr_dword = dsdt_anycpu_qemu_xen_aml_adr_dword,
+        .aml_ej0_name_len = dsdt_anycpu_qemu_xen_aml_ej0_name_len,
+        .aml_adr_dword_len = dsdt_anycpu_qemu_xen_aml_adr_dword_len,
     };
 
     acpi_build_tables(&config, rsdp);
diff --git a/tools/firmware/hvmloader/tools/acpi_extract.py b/tools/firmware/hvmloader/tools/acpi_extract.py
new file mode 100644
index 0000000..4fa51f7
--- /dev/null
+++ b/tools/firmware/hvmloader/tools/acpi_extract.py
@@ -0,0 +1,308 @@
+#!/usr/bin/python
+# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+# Process mixed ASL/AML listing (.lst file) produced by iasl -l
+# Locate and execute ACPI_EXTRACT directives, output offset info
+# 
+# Documentation of ACPI_EXTRACT_* directive tags:
+# 
+# These directive tags output offset information from AML for BIOS runtime
+# table generation.
+# Each directive is of the form:
+# ACPI_EXTRACT_<TYPE> <array_name> <Operator> (...)
+# and causes the extractor to create an array
+# named <array_name> with offset, in the generated AML,
+# of an object of a given type in the following <Operator>.
+# 
+# A directive must fit on a single code line.
+# 
+# Object type in AML is verified, a mismatch causes a build failure.
+# 
+# Directives and operators currently supported are:
+# ACPI_EXTRACT_NAME_DWORD_CONST - extract a Dword Const object from Name()
+# ACPI_EXTRACT_NAME_WORD_CONST - extract a Word Const object from Name()
+# ACPI_EXTRACT_NAME_BYTE_CONST - extract a Byte Const object from Name()
+# ACPI_EXTRACT_METHOD_STRING - extract a NameString from Method()
+# ACPI_EXTRACT_NAME_STRING - extract a NameString from Name()
+# ACPI_EXTRACT_PROCESSOR_START - start of Processor() block
+# ACPI_EXTRACT_PROCESSOR_STRING - extract a NameString from Processor()
+# ACPI_EXTRACT_PROCESSOR_END - offset at last byte of Processor() + 1
+# ACPI_EXTRACT_PKG_START - start of Package block
+#
+# ACPI_EXTRACT_ALL_CODE - create an array storing the generated AML bytecode
+# 
+# ACPI_EXTRACT is not allowed anywhere else in code, except in comments.
+
+import re;
+import sys;
+import fileinput;
+
+aml = []
+asl = []
+output = {}
+debug = ""
+
+class asl_line:
+    line = None
+    lineno = None
+    aml_offset = None
+
+def die(diag):
+    sys.stderr.write("Error: %s; %s\n" % (diag, debug))
+    sys.exit(1)
+    
+#Store an ASL command, matching AML offset, and input line (for debugging)
+def add_asl(lineno, line):
+    l = asl_line()
+    l.line = line
+    l.lineno = lineno
+    l.aml_offset = len(aml)
+    asl.append(l)
+
+#Store an AML byte sequence
+#Verify that offset output by iasl matches # of bytes so far
+def add_aml(offset, line):
+    o = int(offset, 16);
+    # Sanity check: offset must match size of code so far
+    if (o != len(aml)):
+        die("Offset 0x%x != 0x%x" % (o, len(aml)))
+    # Strip any trailing dots and ASCII dump after "
+    line = re.sub(r'\s*\.*\s*".*$',"", line)
+    # Strip traling whitespace
+    line = re.sub(r'\s+$',"", line)
+    # Strip leading whitespace
+    line = re.sub(r'^\s+',"", line)
+    # Split on whitespace
+    code = re.split(r'\s+', line)
+    for c in code:
+        # Require a legal hex number, two digits
+        if (not(re.search(r'^[0-9A-Fa-f][0-9A-Fa-f]$', c))):
+            die("Unexpected octet %s" % c);
+        aml.append(int(c, 16));
+
+# Process aml bytecode array, decoding AML
+def aml_pkglen_bytes(offset):
+    # PkgLength can be multibyte. Bits 8-7 give the # of extra bytes.
+    pkglenbytes = aml[offset] >> 6;
+    return pkglenbytes + 1
+
+def aml_pkglen(offset):
+    pkgstart = offset
+    pkglenbytes = aml_pkglen_bytes(offset)
+    pkglen = aml[offset] & 0x3F
+    # If multibyte, first nibble only uses bits 0-3
+    if ((pkglenbytes > 0) and (pkglen & 0x30)):
+        die("PkgLen bytes 0x%x but first nibble 0x%x expected 0x0X" %
+            (pkglen, pkglen))
+    offset += 1
+    pkglenbytes -= 1
+    for i in range(pkglenbytes):
+        pkglen |= aml[offset + i] << (i * 8 + 4)
+    if (len(aml) < pkgstart + pkglen):
+        die("PckgLen 0x%x at offset 0x%x exceeds AML size 0x%x" %
+            (pkglen, offset, len(aml)))
+    return pkglen
+
+# Given method offset, find its NameString offset
+def aml_method_string(offset):
+    #0x14 MethodOp PkgLength NameString MethodFlags TermList
+    if (aml[offset] != 0x14):
+        die( "Method offset 0x%x: expected 0x14 actual 0x%x" %
+             (offset, aml[offset]));
+    offset += 1;
+    pkglenbytes = aml_pkglen_bytes(offset)
+    offset += pkglenbytes;
+    return offset;
+
+# Given name offset, find its NameString offset
+def aml_name_string(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x08):
+        die( "Name offset 0x%x: expected 0x08 actual 0x%x" %
+             (offset, aml[offset]));
+    offset += 1
+    # Block Name Modifier. Skip it.
+    if (aml[offset] == 0x5c or aml[offset] == 0x5e):
+        offset += 1
+    return offset;
+
+# Given data offset, find dword const offset
+def aml_data_dword_const(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x0C):
+        die( "Name offset 0x%x: expected 0x0C actual 0x%x" %
+             (offset, aml[offset]));
+    return offset + 1;
+
+# Given data offset, find word const offset
+def aml_data_word_const(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x0B):
+        die( "Name offset 0x%x: expected 0x0B actual 0x%x" %
+             (offset, aml[offset]));
+    return offset + 1;
+
+# Given data offset, find byte const offset
+def aml_data_byte_const(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x0A):
+        die( "Name offset 0x%x: expected 0x0A actual 0x%x" %
+             (offset, aml[offset]));
+    return offset + 1;
+
+# Given name offset, find dword const offset
+def aml_name_dword_const(offset):
+    return aml_data_dword_const(aml_name_string(offset) + 4)
+
+# Given name offset, find word const offset
+def aml_name_word_const(offset):
+    return aml_data_word_const(aml_name_string(offset) + 4)
+
+# Given name offset, find byte const offset
+def aml_name_byte_const(offset):
+    return aml_data_byte_const(aml_name_string(offset) + 4)
+
+def aml_processor_start(offset):
+    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
+    if ((aml[offset] != 0x5B) or (aml[offset + 1] != 0x83)):
+        die( "Name offset 0x%x: expected 0x5B 0x83 actual 0x%x 0x%x" %
+             (offset, aml[offset], aml[offset + 1]));
+    return offset
+
+def aml_processor_string(offset):
+    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
+    start = aml_processor_start(offset)
+    offset += 2
+    pkglenbytes = aml_pkglen_bytes(offset)
+    offset += pkglenbytes
+    return offset
+
+def aml_processor_end(offset):
+    start = aml_processor_start(offset)
+    offset += 2
+    pkglenbytes = aml_pkglen_bytes(offset)
+    pkglen = aml_pkglen(offset)
+    return offset + pkglen
+
+def aml_package_start(offset):
+    offset = aml_name_string(offset) + 4
+    # 0x12 PkgLength NumElements PackageElementList
+    if (aml[offset] != 0x12):
+        die( "Name offset 0x%x: expected 0x12 actual 0x%x" %
+             (offset, aml[offset]));
+    offset += 1
+    return offset + aml_pkglen_bytes(offset) + 1
+
+lineno = 0
+for line in fileinput.input():
+    # Strip trailing newline
+    line = line.rstrip();
+    # line number and debug string to output in case of errors
+    lineno = lineno + 1
+    debug = "input line %d: %s" % (lineno, line)
+    #ASL listing: space, then line#, then ...., then code
+    pasl = re.compile('^\s+([0-9]+)\.\.\.\.\s*')
+    m = pasl.search(line)
+    if (m):
+        add_asl(lineno, pasl.sub("", line));
+    # AML listing: offset in hex, then ...., then code
+    paml = re.compile('^([0-9A-Fa-f]+)\.\.\.\.\s*')
+    m = paml.search(line)
+    if (m):
+        add_aml(m.group(1), paml.sub("", line))
+
+# Now go over code
+# Track AML offset of a previous non-empty ASL command
+prev_aml_offset = -1
+for i in range(len(asl)):
+    debug = "input line %d: %s" % (asl[i].lineno, asl[i].line)
+
+    l = asl[i].line
+
+    # skip if not an extract directive
+    a = len(re.findall(r'ACPI_EXTRACT', l))
+    if (not a):
+        # If not empty, store AML offset. Will be used for sanity checks
+        # IASL seems to put {}. at random places in the listing.
+        # Ignore any non-words for the purpose of this test.
+        m = re.search(r'\w+', l)
+        if (m):
+                prev_aml_offset = asl[i].aml_offset
+        continue
+
+    if (a > 1):
+        die("Expected at most one ACPI_EXTRACT per line, actual %d" % a)
+
+    mext = re.search(r'''
+                      ^\s* # leading whitespace
+                      /\*\s* # start C comment
+                      (ACPI_EXTRACT_\w+) # directive: group(1)
+                      \s+ # whitspace separates directive from array name
+                      (\w+) # array name: group(2)
+                      \s*\*/ # end of C comment
+                      \s*$ # trailing whitespace
+                      ''', l, re.VERBOSE)
+    if (not mext):
+        die("Stray ACPI_EXTRACT in input")
+
+    # previous command must have produced some AML,
+    # otherwise we are in a middle of a block
+    if (prev_aml_offset == asl[i].aml_offset):
+        die("ACPI_EXTRACT directive in the middle of a block")
+
+    directive = mext.group(1)
+    array = mext.group(2)
+    offset = asl[i].aml_offset
+
+    if (directive == "ACPI_EXTRACT_ALL_CODE"):
+        if array in output:
+            die("%s directive used more than once" % directive)
+        output[array] = aml
+        continue
+    if (directive == "ACPI_EXTRACT_NAME_DWORD_CONST"):
+        offset = aml_name_dword_const(offset)
+    elif (directive == "ACPI_EXTRACT_NAME_WORD_CONST"):
+        offset = aml_name_word_const(offset)
+    elif (directive == "ACPI_EXTRACT_NAME_BYTE_CONST"):
+        offset = aml_name_byte_const(offset)
+    elif (directive == "ACPI_EXTRACT_NAME_STRING"):
+        offset = aml_name_string(offset)
+    elif (directive == "ACPI_EXTRACT_METHOD_STRING"):
+        offset = aml_method_string(offset)
+    elif (directive == "ACPI_EXTRACT_PROCESSOR_START"):
+        offset = aml_processor_start(offset)
+    elif (directive == "ACPI_EXTRACT_PROCESSOR_STRING"):
+        offset = aml_processor_string(offset)
+    elif (directive == "ACPI_EXTRACT_PROCESSOR_END"):
+        offset = aml_processor_end(offset)
+    elif (directive == "ACPI_EXTRACT_PKG_START"):
+        offset = aml_package_start(offset)
+    else:
+        die("Unsupported directive %s" % directive)
+
+    if array not in output:
+        output[array] = []
+    output[array].append(offset)
+
+debug = "at end of file"
+
+def get_value_type(maxvalue):
+    #Use type large enough to fit the table
+    if (maxvalue >= 0x10000):
+            return "int"
+    elif (maxvalue >= 0x100):
+            return "short"
+    else:
+            return "char"
+
+# Pretty print output
+for array in output.keys():
+    otype = get_value_type(max(output[array]))
+    odata = []
+    for value in output[array]:
+        odata.append("0x%x" % value)
+    sys.stdout.write("unsigned %s %s[] = {\n" % (otype, array))
+    sys.stdout.write(",\n".join(odata))
+    sys.stdout.write('\n};\n');
diff --git a/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py b/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py
new file mode 100644
index 0000000..4ae364e
--- /dev/null
+++ b/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py
@@ -0,0 +1,41 @@
+#!/usr/bin/python
+# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+# Read a preprocessed ASL listing and put each ACPI_EXTRACT
+# directive in a comment, to make iasl skip it.
+# We also put each directive on a new line, the machinery
+# in tools/acpi_extract.py requires this.
+
+import re;
+import sys;
+import fileinput;
+
+def die(diag):
+    sys.stderr.write("Error: %s\n" % (diag))
+    sys.exit(1)
+
+# Note: () around pattern make split return matched string as part of list
+psplit = re.compile(r''' (
+                          \b # At word boundary
+                          ACPI_EXTRACT_\w+ # directive
+                          \s+ # some whitespace
+                          \w+ # array name
+                         )''', re.VERBOSE);
+
+lineno = 0
+for line in fileinput.input():
+    # line number and debug string to output in case of errors
+    lineno = lineno + 1
+    debug = "input line %d: %s" % (lineno, line.rstrip())
+
+    s = psplit.split(line);
+    # The way split works, each odd item is the matching ACPI_EXTRACT directive.
+    # Put each in a comment, and on a line by itself.
+    for i in range(len(s)):
+        if (i % 2):
+            sys.stdout.write("\n/* %s */\n" % s[i])
+        else:
+            sys.stdout.write(s[i])
+
-- 
1.8.3.4


[-- Attachment #3: 4.3.0.patch --]
[-- Type: application/octet-stream, Size: 23126 bytes --]

From ba9f86748620e61768c59b2efcf399b8fd6b435c Mon Sep 17 00:00:00 2001
From: gaowei <gao.gaowei@huawei.com>
Date: Tue, 22 Oct 2013 11:56:46 +0800
Subject: [PATCH] for Test

Signed-off-by: gaowei <gao.gaowei@huawei.com>
---
 tools/firmware/hvmloader/acpi/Makefile             |  46 ++-
 tools/firmware/hvmloader/acpi/acpi2_0.h            |   5 +
 tools/firmware/hvmloader/acpi/build.c              |  24 +-
 tools/firmware/hvmloader/acpi/dsdt.asl             |   1 +
 tools/firmware/hvmloader/acpi/mk_dsdt.c            |   2 +
 tools/firmware/hvmloader/mkhex                     |   0
 tools/firmware/hvmloader/ovmf.c                    |   6 +-
 tools/firmware/hvmloader/rombios.c                 |   4 +
 tools/firmware/hvmloader/seabios.c                 |   8 +
 tools/firmware/hvmloader/tools/acpi_extract.py     | 308 +++++++++++++++++++++
 .../hvmloader/tools/acpi_extract_preprocess.py     |  41 +++
 11 files changed, 431 insertions(+), 14 deletions(-)
 mode change 100755 => 100644 tools/firmware/hvmloader/mkhex
 create mode 100644 tools/firmware/hvmloader/tools/acpi_extract.py
 create mode 100644 tools/firmware/hvmloader/tools/acpi_extract_preprocess.py

diff --git a/tools/firmware/hvmloader/acpi/Makefile b/tools/firmware/hvmloader/acpi/Makefile
index 2c50851..8b3f7ac 100644
--- a/tools/firmware/hvmloader/acpi/Makefile
+++ b/tools/firmware/hvmloader/acpi/Makefile
@@ -24,30 +24,46 @@ OBJS  = $(patsubst %.c,%.o,$(C_SRC))
 CFLAGS += $(CFLAGS_xeninclude)
 
 vpath iasl $(PATH)
+vpath python $(PATH)
+
+.DELETE_ON_ERROR:$(filter dsdt_%.c,$(C_SRC))
+
 all: acpi.a
 
 ssdt_s3.h ssdt_s4.h ssdt_pm.h ssdt_tpm.h: %.h: %.asl iasl
 	iasl -vs -p $* -tc $<
-	sed -e 's/AmlCode/$*/g' $*.hex >$@
+	sed -e 's/AmlCode/$*/g' $*.hex >$@.tmp
+	$(call move-if-changed,$@.tmp $@)
 	rm -f $*.hex $*.aml
 
 mk_dsdt: mk_dsdt.c
 	$(HOSTCC) $(HOSTCFLAGS) $(CFLAGS_xeninclude) -o $@ mk_dsdt.c
 
 dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
-	awk 'NR > 1 {print s} {s=$$0}' $< > $@
-	./mk_dsdt --dm-version qemu-xen >> $@
-
+	awk 'NR > 1 {print s} {s=$$0}' $< > $@.tmp
+	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@.tmp
+	./mk_dsdt --dm-version qemu-xen >> $@.tmp
+	sed -i 's/aml_ej0_name/dsdt_anycpu_qemu_xen_aml_ej0_name/g' $@.tmp
+	sed -i 's/aml_adr_dword/dsdt_anycpu_qemu_xen_aml_adr_dword/g' $@.tmp
+	$(call move-if-changed,$@.tmp $@)
+	
 # NB. awk invocation is a portable alternative to 'head -n -1'
 dsdt_%cpu.asl: dsdt.asl mk_dsdt
-	awk 'NR > 1 {print s} {s=$$0}' $< > $@
-	./mk_dsdt --maxcpu $*  >> $@
+	awk 'NR > 1 {print s} {s=$$0}' $< > $@.tmp
+	sed -i 's/AmlCode/dsdt_$*cpu/g' $@.tmp
+	./mk_dsdt --maxcpu $*  >> $@.tmp
+	$(call move-if-changed,$@.tmp $@)
 
-$(filter dsdt_%.c,$(C_SRC)): %.c: iasl %.asl
-	iasl -vs -p $* -tc $*.asl
-	sed -e 's/AmlCode/$*/g' $*.hex >$@
-	echo "int $*_len=sizeof($*);" >>$@
-	rm -f $*.aml $*.hex
+$(filter dsdt_%.c,$(C_SRC)): %.c: iasl python %.asl
+	cpp -P $*.asl > $*.asl.i.orig
+	python ../tools/acpi_extract_preprocess.py $*.asl.i.orig > $*.asl.i
+	iasl -vs -l -tc -p $* $*.asl.i
+	python ../tools/acpi_extract.py $*.lst > $@.tmp
+	echo "int $*_len=sizeof($*);" >>$@.tmp
+	if grep -q "$*_aml_ej0_name" $@.tmp; then echo "int $*_aml_ej0_name_len=sizeof($*_aml_ej0_name);" >>$@.tmp; fi
+	if grep -q "$*_aml_adr_dword" $@.tmp; then echo "int $*_aml_adr_dword_len=sizeof($*_aml_adr_dword);" >>$@.tmp;fi
+	$(call move-if-changed,$@.tmp $@)
+	rm -f $*.aml $*.hex $*.asl.i.orig $*.asl.i $*.lst
 
 iasl:
 	@echo
@@ -57,6 +73,12 @@ iasl:
 	@echo 
 	@exit 1
 
+python:
+	@echo
+	@echo "python is needed"
+	@echo
+	@exit 1
+
 build.o: ssdt_s3.h ssdt_s4.h ssdt_pm.h ssdt_tpm.h
 
 acpi.a: $(OBJS)
@@ -64,7 +86,7 @@ acpi.a: $(OBJS)
 
 clean:
 	rm -rf *.a *.o $(IASL_VER) $(IASL_VER).tar.gz $(DEPS)
-	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl
+	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl *.asl.i *.asl.i.orig *.lst *.tmp
 
 install: all
 
diff --git a/tools/firmware/hvmloader/acpi/acpi2_0.h b/tools/firmware/hvmloader/acpi/acpi2_0.h
index 7b22d80..d0c83b8 100644
--- a/tools/firmware/hvmloader/acpi/acpi2_0.h
+++ b/tools/firmware/hvmloader/acpi/acpi2_0.h
@@ -396,6 +396,11 @@ struct acpi_config {
     int dsdt_anycpu_len;
     unsigned char *dsdt_15cpu;
     int dsdt_15cpu_len;
+    unsigned short *aml_ej0_name;
+    unsigned short *aml_adr_dword;
+    int aml_ej0_name_len;
+    int aml_adr_dword_len;
+    
 };
 
 void acpi_build_tables(struct acpi_config *config, unsigned int physical);
diff --git a/tools/firmware/hvmloader/acpi/build.c b/tools/firmware/hvmloader/acpi/build.c
index 7281b97..e3a83d8 100644
--- a/tools/firmware/hvmloader/acpi/build.c
+++ b/tools/firmware/hvmloader/acpi/build.c
@@ -30,6 +30,9 @@
 #define align16(sz)        (((sz) + 15) & ~15)
 #define fixed_strcpy(d, s) strncpy((d), (s), sizeof(d))
 
+
+#define PCI_RMV_BASE 0xae0c
+
 extern struct acpi_20_rsdp Rsdp;
 extern struct acpi_20_rsdt Rsdt;
 extern struct acpi_20_xsdt Xsdt;
@@ -402,6 +405,7 @@ void acpi_build_tables(struct acpi_config *config, unsigned int physical)
     unsigned char       *dsdt;
     unsigned long        secondary_tables[ACPI_MAX_SECONDARY_TABLES];
     int                  nr_secondaries, i;
+    unsigned int rmvc_pcrm = 0;
 
     /* Allocate and initialise the acpi info area. */
     mem_hole_populate_ram(ACPI_INFO_PHYSICAL_ADDRESS >> PAGE_SHIFT, 1);
@@ -436,9 +440,27 @@ void acpi_build_tables(struct acpi_config *config, unsigned int physical)
         dsdt = mem_alloc(config->dsdt_anycpu_len, 16);
         if (!dsdt) goto oom;
         memcpy(dsdt, config->dsdt_anycpu, config->dsdt_anycpu_len);
-        nr_processor_objects = HVM_MAX_VCPUS;
+        if(config->aml_adr_dword_len && config->aml_ej0_name_len &&
+            (config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]) == config->aml_ej0_name_len/sizeof(config->aml_ej0_name[0])))
+        {
+            rmvc_pcrm = inl(PCI_RMV_BASE); 
+            printf("rmvc_pcrm is %x\n", rmvc_pcrm);
+            for(i = 0;  i < config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]); i ++)
+            {
+                /* Slot is in byte 2 in _ADR */
+                unsigned char slot = dsdt[config->aml_adr_dword[i] + 2] & 0x1F;
+                /* Sanity check */
+                if (memcmp(dsdt + config->aml_ej0_name[i], "_EJ0", 4)) {
+                    goto oom;
+                }
+                if (!(rmvc_pcrm & (0x1 << slot))) {
+                    memcpy(dsdt + config->aml_ej0_name[i], "EJ0_", 4);
+                }
+            }
+        }
     }
 
+    nr_processor_objects = HVM_MAX_VCPUS;
     /*
      * N.B. ACPI 1.0 operating systems may not handle FADT with revision 2
      * or above properly, notably Windows 2000, which tries to copy FADT
diff --git a/tools/firmware/hvmloader/acpi/dsdt.asl b/tools/firmware/hvmloader/acpi/dsdt.asl
index 247a8ad..1e7695b 100644
--- a/tools/firmware/hvmloader/acpi/dsdt.asl
+++ b/tools/firmware/hvmloader/acpi/dsdt.asl
@@ -16,6 +16,7 @@
  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  * Place - Suite 330, Boston, MA 02111-1307 USA.
  */
+ACPI_EXTRACT_ALL_CODE AmlCode
 
 DefinitionBlock ("DSDT.aml", "DSDT", 2, "Xen", "HVM", 0)
 {
diff --git a/tools/firmware/hvmloader/acpi/mk_dsdt.c b/tools/firmware/hvmloader/acpi/mk_dsdt.c
index 996f30b..4180801 100644
--- a/tools/firmware/hvmloader/acpi/mk_dsdt.c
+++ b/tools/firmware/hvmloader/acpi/mk_dsdt.c
@@ -368,7 +368,9 @@ int main(int argc, char **argv)
         /* hotplug_slot */
         for (slot = 1; slot <= 31; slot++) {
             push_block("Device", "S%i", slot); {
+                printf("ACPI_EXTRACT_NAME_DWORD_CONST aml_adr_dword\n");
                 stmt("Name", "_ADR, %#06x0000", slot);
+                printf("ACPI_EXTRACT_METHOD_STRING aml_ej0_name\n");
                 push_block("Method", "_EJ0,1"); {
                     stmt("Store", "ShiftLeft(1, %#06x), B0EJ", slot);
                     stmt("Return", "0x0");
diff --git a/tools/firmware/hvmloader/mkhex b/tools/firmware/hvmloader/mkhex
old mode 100755
new mode 100644
diff --git a/tools/firmware/hvmloader/ovmf.c b/tools/firmware/hvmloader/ovmf.c
index ee4cbbf..27ff0b5 100644
--- a/tools/firmware/hvmloader/ovmf.c
+++ b/tools/firmware/hvmloader/ovmf.c
@@ -79,7 +79,11 @@ static void ovmf_acpi_build_tables(void)
         .dsdt_anycpu = dsdt_anycpu,
         .dsdt_anycpu_len = dsdt_anycpu_len,
         .dsdt_15cpu = NULL, 
-        .dsdt_15cpu_len = 0
+        .dsdt_15cpu_len = 0,
+        .aml_ej0_name = NULL,
+        .aml_adr_dword = NULL,
+        .aml_ej0_name_len = 0,
+        .aml_adr_dword_len = 0,
     };
 
     acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
diff --git a/tools/firmware/hvmloader/rombios.c b/tools/firmware/hvmloader/rombios.c
index f6f5310..a8b7f95 100644
--- a/tools/firmware/hvmloader/rombios.c
+++ b/tools/firmware/hvmloader/rombios.c
@@ -177,6 +177,10 @@ static void rombios_acpi_build_tables(void)
         .dsdt_anycpu_len = dsdt_anycpu_len,
         .dsdt_15cpu = dsdt_15cpu,
         .dsdt_15cpu_len = dsdt_15cpu_len,
+        .aml_ej0_name = NULL,
+        .aml_adr_dword = NULL,
+        .aml_ej0_name_len = 0,
+        .aml_adr_dword_len = 0,
     };
 
     acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
diff --git a/tools/firmware/hvmloader/seabios.c b/tools/firmware/hvmloader/seabios.c
index f17e67b..8b3a85f 100644
--- a/tools/firmware/hvmloader/seabios.c
+++ b/tools/firmware/hvmloader/seabios.c
@@ -33,6 +33,10 @@
 
 extern unsigned char dsdt_anycpu_qemu_xen[];
 extern int dsdt_anycpu_qemu_xen_len;
+extern unsigned short dsdt_anycpu_qemu_xen_aml_ej0_name[];
+extern unsigned short dsdt_anycpu_qemu_xen_aml_adr_dword[];
+extern int dsdt_anycpu_qemu_xen_aml_ej0_name_len;
+extern int dsdt_anycpu_qemu_xen_aml_adr_dword_len;
 
 struct seabios_info {
     char signature[14]; /* XenHVMSeaBIOS\0 */
@@ -99,6 +103,10 @@ static void seabios_acpi_build_tables(void)
         .dsdt_anycpu_len = dsdt_anycpu_qemu_xen_len,
         .dsdt_15cpu = NULL,
         .dsdt_15cpu_len = 0,
+        .aml_ej0_name = dsdt_anycpu_qemu_xen_aml_ej0_name,
+        .aml_adr_dword = dsdt_anycpu_qemu_xen_aml_adr_dword,
+        .aml_ej0_name_len = dsdt_anycpu_qemu_xen_aml_ej0_name_len,
+        .aml_adr_dword_len = dsdt_anycpu_qemu_xen_aml_adr_dword_len,
     };
 
     acpi_build_tables(&config, rsdp);
diff --git a/tools/firmware/hvmloader/tools/acpi_extract.py b/tools/firmware/hvmloader/tools/acpi_extract.py
new file mode 100644
index 0000000..4fa51f7
--- /dev/null
+++ b/tools/firmware/hvmloader/tools/acpi_extract.py
@@ -0,0 +1,308 @@
+#!/usr/bin/python
+# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+# Process mixed ASL/AML listing (.lst file) produced by iasl -l
+# Locate and execute ACPI_EXTRACT directives, output offset info
+# 
+# Documentation of ACPI_EXTRACT_* directive tags:
+# 
+# These directive tags output offset information from AML for BIOS runtime
+# table generation.
+# Each directive is of the form:
+# ACPI_EXTRACT_<TYPE> <array_name> <Operator> (...)
+# and causes the extractor to create an array
+# named <array_name> with offset, in the generated AML,
+# of an object of a given type in the following <Operator>.
+# 
+# A directive must fit on a single code line.
+# 
+# Object type in AML is verified, a mismatch causes a build failure.
+# 
+# Directives and operators currently supported are:
+# ACPI_EXTRACT_NAME_DWORD_CONST - extract a Dword Const object from Name()
+# ACPI_EXTRACT_NAME_WORD_CONST - extract a Word Const object from Name()
+# ACPI_EXTRACT_NAME_BYTE_CONST - extract a Byte Const object from Name()
+# ACPI_EXTRACT_METHOD_STRING - extract a NameString from Method()
+# ACPI_EXTRACT_NAME_STRING - extract a NameString from Name()
+# ACPI_EXTRACT_PROCESSOR_START - start of Processor() block
+# ACPI_EXTRACT_PROCESSOR_STRING - extract a NameString from Processor()
+# ACPI_EXTRACT_PROCESSOR_END - offset at last byte of Processor() + 1
+# ACPI_EXTRACT_PKG_START - start of Package block
+#
+# ACPI_EXTRACT_ALL_CODE - create an array storing the generated AML bytecode
+# 
+# ACPI_EXTRACT is not allowed anywhere else in code, except in comments.
+
+import re;
+import sys;
+import fileinput;
+
+aml = []
+asl = []
+output = {}
+debug = ""
+
+class asl_line:
+    line = None
+    lineno = None
+    aml_offset = None
+
+def die(diag):
+    sys.stderr.write("Error: %s; %s\n" % (diag, debug))
+    sys.exit(1)
+    
+#Store an ASL command, matching AML offset, and input line (for debugging)
+def add_asl(lineno, line):
+    l = asl_line()
+    l.line = line
+    l.lineno = lineno
+    l.aml_offset = len(aml)
+    asl.append(l)
+
+#Store an AML byte sequence
+#Verify that offset output by iasl matches # of bytes so far
+def add_aml(offset, line):
+    o = int(offset, 16);
+    # Sanity check: offset must match size of code so far
+    if (o != len(aml)):
+        die("Offset 0x%x != 0x%x" % (o, len(aml)))
+    # Strip any trailing dots and ASCII dump after "
+    line = re.sub(r'\s*\.*\s*".*$',"", line)
+    # Strip traling whitespace
+    line = re.sub(r'\s+$',"", line)
+    # Strip leading whitespace
+    line = re.sub(r'^\s+',"", line)
+    # Split on whitespace
+    code = re.split(r'\s+', line)
+    for c in code:
+        # Require a legal hex number, two digits
+        if (not(re.search(r'^[0-9A-Fa-f][0-9A-Fa-f]$', c))):
+            die("Unexpected octet %s" % c);
+        aml.append(int(c, 16));
+
+# Process aml bytecode array, decoding AML
+def aml_pkglen_bytes(offset):
+    # PkgLength can be multibyte. Bits 8-7 give the # of extra bytes.
+    pkglenbytes = aml[offset] >> 6;
+    return pkglenbytes + 1
+
+def aml_pkglen(offset):
+    pkgstart = offset
+    pkglenbytes = aml_pkglen_bytes(offset)
+    pkglen = aml[offset] & 0x3F
+    # If multibyte, first nibble only uses bits 0-3
+    if ((pkglenbytes > 0) and (pkglen & 0x30)):
+        die("PkgLen bytes 0x%x but first nibble 0x%x expected 0x0X" %
+            (pkglen, pkglen))
+    offset += 1
+    pkglenbytes -= 1
+    for i in range(pkglenbytes):
+        pkglen |= aml[offset + i] << (i * 8 + 4)
+    if (len(aml) < pkgstart + pkglen):
+        die("PckgLen 0x%x at offset 0x%x exceeds AML size 0x%x" %
+            (pkglen, offset, len(aml)))
+    return pkglen
+
+# Given method offset, find its NameString offset
+def aml_method_string(offset):
+    #0x14 MethodOp PkgLength NameString MethodFlags TermList
+    if (aml[offset] != 0x14):
+        die( "Method offset 0x%x: expected 0x14 actual 0x%x" %
+             (offset, aml[offset]));
+    offset += 1;
+    pkglenbytes = aml_pkglen_bytes(offset)
+    offset += pkglenbytes;
+    return offset;
+
+# Given name offset, find its NameString offset
+def aml_name_string(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x08):
+        die( "Name offset 0x%x: expected 0x08 actual 0x%x" %
+             (offset, aml[offset]));
+    offset += 1
+    # Block Name Modifier. Skip it.
+    if (aml[offset] == 0x5c or aml[offset] == 0x5e):
+        offset += 1
+    return offset;
+
+# Given data offset, find dword const offset
+def aml_data_dword_const(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x0C):
+        die( "Name offset 0x%x: expected 0x0C actual 0x%x" %
+             (offset, aml[offset]));
+    return offset + 1;
+
+# Given data offset, find word const offset
+def aml_data_word_const(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x0B):
+        die( "Name offset 0x%x: expected 0x0B actual 0x%x" %
+             (offset, aml[offset]));
+    return offset + 1;
+
+# Given data offset, find byte const offset
+def aml_data_byte_const(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x0A):
+        die( "Name offset 0x%x: expected 0x0A actual 0x%x" %
+             (offset, aml[offset]));
+    return offset + 1;
+
+# Given name offset, find dword const offset
+def aml_name_dword_const(offset):
+    return aml_data_dword_const(aml_name_string(offset) + 4)
+
+# Given name offset, find word const offset
+def aml_name_word_const(offset):
+    return aml_data_word_const(aml_name_string(offset) + 4)
+
+# Given name offset, find byte const offset
+def aml_name_byte_const(offset):
+    return aml_data_byte_const(aml_name_string(offset) + 4)
+
+def aml_processor_start(offset):
+    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
+    if ((aml[offset] != 0x5B) or (aml[offset + 1] != 0x83)):
+        die( "Name offset 0x%x: expected 0x5B 0x83 actual 0x%x 0x%x" %
+             (offset, aml[offset], aml[offset + 1]));
+    return offset
+
+def aml_processor_string(offset):
+    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
+    start = aml_processor_start(offset)
+    offset += 2
+    pkglenbytes = aml_pkglen_bytes(offset)
+    offset += pkglenbytes
+    return offset
+
+def aml_processor_end(offset):
+    start = aml_processor_start(offset)
+    offset += 2
+    pkglenbytes = aml_pkglen_bytes(offset)
+    pkglen = aml_pkglen(offset)
+    return offset + pkglen
+
+def aml_package_start(offset):
+    offset = aml_name_string(offset) + 4
+    # 0x12 PkgLength NumElements PackageElementList
+    if (aml[offset] != 0x12):
+        die( "Name offset 0x%x: expected 0x12 actual 0x%x" %
+             (offset, aml[offset]));
+    offset += 1
+    return offset + aml_pkglen_bytes(offset) + 1
+
+lineno = 0
+for line in fileinput.input():
+    # Strip trailing newline
+    line = line.rstrip();
+    # line number and debug string to output in case of errors
+    lineno = lineno + 1
+    debug = "input line %d: %s" % (lineno, line)
+    #ASL listing: space, then line#, then ...., then code
+    pasl = re.compile('^\s+([0-9]+)\.\.\.\.\s*')
+    m = pasl.search(line)
+    if (m):
+        add_asl(lineno, pasl.sub("", line));
+    # AML listing: offset in hex, then ...., then code
+    paml = re.compile('^([0-9A-Fa-f]+)\.\.\.\.\s*')
+    m = paml.search(line)
+    if (m):
+        add_aml(m.group(1), paml.sub("", line))
+
+# Now go over code
+# Track AML offset of a previous non-empty ASL command
+prev_aml_offset = -1
+for i in range(len(asl)):
+    debug = "input line %d: %s" % (asl[i].lineno, asl[i].line)
+
+    l = asl[i].line
+
+    # skip if not an extract directive
+    a = len(re.findall(r'ACPI_EXTRACT', l))
+    if (not a):
+        # If not empty, store AML offset. Will be used for sanity checks
+        # IASL seems to put {}. at random places in the listing.
+        # Ignore any non-words for the purpose of this test.
+        m = re.search(r'\w+', l)
+        if (m):
+                prev_aml_offset = asl[i].aml_offset
+        continue
+
+    if (a > 1):
+        die("Expected at most one ACPI_EXTRACT per line, actual %d" % a)
+
+    mext = re.search(r'''
+                      ^\s* # leading whitespace
+                      /\*\s* # start C comment
+                      (ACPI_EXTRACT_\w+) # directive: group(1)
+                      \s+ # whitspace separates directive from array name
+                      (\w+) # array name: group(2)
+                      \s*\*/ # end of C comment
+                      \s*$ # trailing whitespace
+                      ''', l, re.VERBOSE)
+    if (not mext):
+        die("Stray ACPI_EXTRACT in input")
+
+    # previous command must have produced some AML,
+    # otherwise we are in a middle of a block
+    if (prev_aml_offset == asl[i].aml_offset):
+        die("ACPI_EXTRACT directive in the middle of a block")
+
+    directive = mext.group(1)
+    array = mext.group(2)
+    offset = asl[i].aml_offset
+
+    if (directive == "ACPI_EXTRACT_ALL_CODE"):
+        if array in output:
+            die("%s directive used more than once" % directive)
+        output[array] = aml
+        continue
+    if (directive == "ACPI_EXTRACT_NAME_DWORD_CONST"):
+        offset = aml_name_dword_const(offset)
+    elif (directive == "ACPI_EXTRACT_NAME_WORD_CONST"):
+        offset = aml_name_word_const(offset)
+    elif (directive == "ACPI_EXTRACT_NAME_BYTE_CONST"):
+        offset = aml_name_byte_const(offset)
+    elif (directive == "ACPI_EXTRACT_NAME_STRING"):
+        offset = aml_name_string(offset)
+    elif (directive == "ACPI_EXTRACT_METHOD_STRING"):
+        offset = aml_method_string(offset)
+    elif (directive == "ACPI_EXTRACT_PROCESSOR_START"):
+        offset = aml_processor_start(offset)
+    elif (directive == "ACPI_EXTRACT_PROCESSOR_STRING"):
+        offset = aml_processor_string(offset)
+    elif (directive == "ACPI_EXTRACT_PROCESSOR_END"):
+        offset = aml_processor_end(offset)
+    elif (directive == "ACPI_EXTRACT_PKG_START"):
+        offset = aml_package_start(offset)
+    else:
+        die("Unsupported directive %s" % directive)
+
+    if array not in output:
+        output[array] = []
+    output[array].append(offset)
+
+debug = "at end of file"
+
+def get_value_type(maxvalue):
+    #Use type large enough to fit the table
+    if (maxvalue >= 0x10000):
+            return "int"
+    elif (maxvalue >= 0x100):
+            return "short"
+    else:
+            return "char"
+
+# Pretty print output
+for array in output.keys():
+    otype = get_value_type(max(output[array]))
+    odata = []
+    for value in output[array]:
+        odata.append("0x%x" % value)
+    sys.stdout.write("unsigned %s %s[] = {\n" % (otype, array))
+    sys.stdout.write(",\n".join(odata))
+    sys.stdout.write('\n};\n');
diff --git a/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py b/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py
new file mode 100644
index 0000000..4ae364e
--- /dev/null
+++ b/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py
@@ -0,0 +1,41 @@
+#!/usr/bin/python
+# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+# Read a preprocessed ASL listing and put each ACPI_EXTRACT
+# directive in a comment, to make iasl skip it.
+# We also put each directive on a new line, the machinery
+# in tools/acpi_extract.py requires this.
+
+import re;
+import sys;
+import fileinput;
+
+def die(diag):
+    sys.stderr.write("Error: %s\n" % (diag))
+    sys.exit(1)
+
+# Note: () around pattern make split return matched string as part of list
+psplit = re.compile(r''' (
+                          \b # At word boundary
+                          ACPI_EXTRACT_\w+ # directive
+                          \s+ # some whitespace
+                          \w+ # array name
+                         )''', re.VERBOSE);
+
+lineno = 0
+for line in fileinput.input():
+    # line number and debug string to output in case of errors
+    lineno = lineno + 1
+    debug = "input line %d: %s" % (lineno, line.rstrip())
+
+    s = psplit.split(line);
+    # The way split works, each odd item is the matching ACPI_EXTRACT directive.
+    # Put each in a comment, and on a line by itself.
+    for i in range(len(s)):
+        if (i % 2):
+            sys.stdout.write("\n/* %s */\n" % s[i])
+        else:
+            sys.stdout.write(s[i])
+
-- 
1.8.3.4


[-- Attachment #4: Type: text/plain, Size: 126 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [Xen-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
  2013-10-22  4:08             ` Gonglei (Arei)
  2013-10-22  8:06               ` [Qemu-devel] " Jan Beulich
@ 2013-10-22  8:06               ` Jan Beulich
  2013-10-24 12:17                 ` [Qemu-devel] " Gonglei (Arei)
                                   ` (3 more replies)
  1 sibling, 4 replies; 38+ messages in thread
From: Jan Beulich @ 2013-10-22  8:06 UTC (permalink / raw)
  To: Gonglei (Arei)
  Cc: Yanqiangjun, Ian Campbell, Hanweidong (Randy),
	Markus Armbruster, Stefano Stabellini, Luonengjun, qemu-devel,
	xen-devel, Fabio Fantoni, anthony.perard, Gaowei (UVP),
	Huangweidong (Hardware)

>>> On 22.10.13 at 06:08, "Gonglei (Arei)" <arei.gonglei@huawei.com> wrote:
> Hi, guys. The new patch has been modified based on the principles you 
> suggested, thank you so much.
> Last time I test the patch based on the codes of 4.3.0.
> This time, I found that the system based on the codes of trunk causes the VM 
> reboot again and again, which I have not found out the reason.
> So i can not test the patch based on the codes of trunk (details in 
> EJ0_ACPI_PCI_Hotplug.patch)..

I'm afraid we will need you to figure out that problem first, and
then do the verification on -unstable. Even if the code shouldn't
be that different from 4.3, we still don't want to apply completely
untested stuff.

> --- a/tools/firmware/hvmloader/acpi/Makefile
> +++ b/tools/firmware/hvmloader/acpi/Makefile
> @@ -24,30 +24,46 @@ OBJS  = $(patsubst %.c,%.o,$(C_SRC))
>  CFLAGS += $(CFLAGS_xeninclude)
>  
>  vpath iasl $(PATH)
> +vpath python $(PATH)

Iirc this ought to be $(PYTHON) (also further down).

> +
> +.DELETE_ON_ERROR:$(filter dsdt_%.c,$(C_SRC))

Missing blank after ":".

>  dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
> -	awk 'NR > 1 {print s} {s=$$0}' $< > $@
> -	./mk_dsdt --dm-version qemu-xen >> $@
> -
> +	awk 'NR > 1 {print s} {s=$$0}' $< > $@.tmp
> +	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@.tmp
> +	./mk_dsdt --dm-version qemu-xen >> $@.tmp
> +	sed -i 's/aml_ej0_name/dsdt_anycpu_qemu_xen_aml_ej0_name/g' $@.tmp
> +	sed -i 's/aml_adr_dword/dsdt_anycpu_qemu_xen_aml_adr_dword/g' $@.tmp
> +	$(call move-if-changed,$@.tmp $@)
> +	

Line containing just a tab.

>  # NB. awk invocation is a portable alternative to 'head -n -1'
>  dsdt_%cpu.asl: dsdt.asl mk_dsdt
> -	awk 'NR > 1 {print s} {s=$$0}' $< > $@
> -	./mk_dsdt --maxcpu $*  >> $@
> +	awk 'NR > 1 {print s} {s=$$0}' $< > $@.tmp
> +	sed -i 's/AmlCode/dsdt_$*cpu/g' $@.tmp
> +	./mk_dsdt --maxcpu $*  >> $@.tmp
> +	$(call move-if-changed,$@.tmp $@)
>  
> -$(filter dsdt_%.c,$(C_SRC)): %.c: iasl %.asl
> -	iasl -vs -p $* -tc $*.asl
> -	sed -e 's/AmlCode/$*/g' $*.hex >$@
> -	echo "int $*_len=sizeof($*);" >>$@
> -	rm -f $*.aml $*.hex
> +$(filter dsdt_%.c,$(C_SRC)): %.c: iasl python %.asl

As you need to touch this anyway, please adjust it to match
common style: The input file should come first in the list of
dependencies, allowing you ...

> +	cpp -P $*.asl > $*.asl.i.orig

... use $< here (and further down where applicable) in favor of $*.

> +	python ../tools/acpi_extract_preprocess.py $*.asl.i.orig > $*.asl.i

Please be consistent in whether you put a blank after ">" and ">>".

> +	iasl -vs -l -tc -p $* $*.asl.i
> +	python ../tools/acpi_extract.py $*.lst > $@.tmp
> +	echo "int $*_len=sizeof($*);" >>$@.tmp
> +	if grep -q "$*_aml_ej0_name" $@.tmp; then echo "int $*_aml_ej0_name_len=sizeof($*_aml_ej0_name);" >>$@.tmp; fi
> +	if grep -q "$*_aml_adr_dword" $@.tmp; then echo "int $*_aml_adr_dword_len=sizeof($*_aml_adr_dword);" >>$@.tmp;fi

Missing blank before "fi".

> +python:
> +	@echo
> +	@echo "python is needed"
> +	@echo
> +	@exit 1

What is this good for? For one, the tools build already requires
Python. And then such a dependency would belong into the
configure scripts, not here.

> --- a/tools/firmware/hvmloader/acpi/build.c
> +++ b/tools/firmware/hvmloader/acpi/build.c

There are various coding style issues in the changes to this file.
Please make sure you match the style found elsewhere in here.

> @@ -30,6 +30,9 @@
>  #define align16(sz)        (((sz) + 15) & ~15)
>  #define fixed_strcpy(d, s) strncpy((d), (s), sizeof(d))
>  
> +
> +#define PCI_RMV_BASE 0xae0c
> +
>  extern struct acpi_20_rsdp Rsdp;
>  extern struct acpi_20_rsdt Rsdt;
>  extern struct acpi_20_xsdt Xsdt;
> @@ -404,6 +407,7 @@ void acpi_build_tables(struct acpi_config *config, unsigned int physical)
>      unsigned char       *dsdt;
>      unsigned long        secondary_tables[ACPI_MAX_SECONDARY_TABLES];
>      int                  nr_secondaries, i;
> +    unsigned int rmvc_pcrm = 0;

Pointless initializer. You'd be better off moving the declaration to
the first use point anyway (and then it can have a proper initializer
right away).

> @@ -438,9 +442,27 @@ void acpi_build_tables(struct acpi_config *config, unsigned int physical)
>          dsdt = mem_alloc(config->dsdt_anycpu_len, 16);
>          if (!dsdt) goto oom;
>          memcpy(dsdt, config->dsdt_anycpu, config->dsdt_anycpu_len);
> -        nr_processor_objects = HVM_MAX_VCPUS;

The movement to this assignment is clearly wrong, as it now
overwrites the different value stored when using the <= 15 CPUs
path.

This also raises the question of why you do the adjustment below
only in the >= 16 CPUs code path.

I also don't see how this adjustment is in line with mk_dsdt.c's
handling of the qemu-traditional case. Or is that building on
SeaBIOS only ever being used with upstream qemu?

> +        if(config->aml_adr_dword_len && config->aml_ej0_name_len &&
> +            (config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]) == config->aml_ej0_name_len/sizeof(config->aml_ej0_name[0])))
> +        {
> +            rmvc_pcrm = inl(PCI_RMV_BASE); 
> +            printf("rmvc_pcrm is %x\n", rmvc_pcrm);
> +            for(i = 0;  i < config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]); i ++)
> +            {
> +                /* Slot is in byte 2 in _ADR */
> +                unsigned char slot = dsdt[config->aml_adr_dword[i] + 2] & 0x1F;
> +                /* Sanity check */
> +                if (memcmp(dsdt + config->aml_ej0_name[i], "_EJ0", 4)) {
> +                    goto oom;

A memcmp() failure should result in a meaningful error message;
definitely not "out of memory".

> +                }
> +                if (!(rmvc_pcrm & (0x1 << slot))) {
> +                    memcpy(dsdt + config->aml_ej0_name[i], "EJ0_", 4);
> +                }
> +            }
> +        }

> --- a/tools/firmware/hvmloader/ovmf.c
> +++ b/tools/firmware/hvmloader/ovmf.c
> @@ -79,7 +79,11 @@ static void ovmf_acpi_build_tables(void)
>          .dsdt_anycpu = dsdt_anycpu,
>          .dsdt_anycpu_len = dsdt_anycpu_len,
>          .dsdt_15cpu = NULL, 
> -        .dsdt_15cpu_len = 0
> +        .dsdt_15cpu_len = 0,
> +        .aml_ej0_name = NULL,
> +        .aml_adr_dword = NULL,
> +        .aml_ej0_name_len = 0,
> +        .aml_adr_dword_len = 0,

I don't see why you're adding these.

> --- a/tools/firmware/hvmloader/rombios.c
> +++ b/tools/firmware/hvmloader/rombios.c
> @@ -179,6 +179,10 @@ static void rombios_acpi_build_tables(void)
>          .dsdt_anycpu_len = dsdt_anycpu_len,
>          .dsdt_15cpu = dsdt_15cpu,
>          .dsdt_15cpu_len = dsdt_15cpu_len,
> +        .aml_ej0_name = NULL,
> +        .aml_adr_dword = NULL,
> +        .aml_ej0_name_len = 0,
> +        .aml_adr_dword_len = 0,

Same here.

Jan

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
  2013-10-22  4:08             ` Gonglei (Arei)
@ 2013-10-22  8:06               ` Jan Beulich
  2013-10-22  8:06               ` [Qemu-devel] [Xen-devel] " Jan Beulich
  1 sibling, 0 replies; 38+ messages in thread
From: Jan Beulich @ 2013-10-22  8:06 UTC (permalink / raw)
  To: Gonglei (Arei)
  Cc: Yanqiangjun, Ian Campbell, Hanweidong (Randy),
	Markus Armbruster, Stefano Stabellini, Luonengjun, qemu-devel,
	xen-devel, Fabio Fantoni, anthony.perard, Gaowei (UVP),
	Huangweidong (Hardware)

>>> On 22.10.13 at 06:08, "Gonglei (Arei)" <arei.gonglei@huawei.com> wrote:
> Hi, guys. The new patch has been modified based on the principles you 
> suggested, thank you so much.
> Last time I test the patch based on the codes of 4.3.0.
> This time, I found that the system based on the codes of trunk causes the VM 
> reboot again and again, which I have not found out the reason.
> So i can not test the patch based on the codes of trunk (details in 
> EJ0_ACPI_PCI_Hotplug.patch)..

I'm afraid we will need you to figure out that problem first, and
then do the verification on -unstable. Even if the code shouldn't
be that different from 4.3, we still don't want to apply completely
untested stuff.

> --- a/tools/firmware/hvmloader/acpi/Makefile
> +++ b/tools/firmware/hvmloader/acpi/Makefile
> @@ -24,30 +24,46 @@ OBJS  = $(patsubst %.c,%.o,$(C_SRC))
>  CFLAGS += $(CFLAGS_xeninclude)
>  
>  vpath iasl $(PATH)
> +vpath python $(PATH)

Iirc this ought to be $(PYTHON) (also further down).

> +
> +.DELETE_ON_ERROR:$(filter dsdt_%.c,$(C_SRC))

Missing blank after ":".

>  dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
> -	awk 'NR > 1 {print s} {s=$$0}' $< > $@
> -	./mk_dsdt --dm-version qemu-xen >> $@
> -
> +	awk 'NR > 1 {print s} {s=$$0}' $< > $@.tmp
> +	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@.tmp
> +	./mk_dsdt --dm-version qemu-xen >> $@.tmp
> +	sed -i 's/aml_ej0_name/dsdt_anycpu_qemu_xen_aml_ej0_name/g' $@.tmp
> +	sed -i 's/aml_adr_dword/dsdt_anycpu_qemu_xen_aml_adr_dword/g' $@.tmp
> +	$(call move-if-changed,$@.tmp $@)
> +	

Line containing just a tab.

>  # NB. awk invocation is a portable alternative to 'head -n -1'
>  dsdt_%cpu.asl: dsdt.asl mk_dsdt
> -	awk 'NR > 1 {print s} {s=$$0}' $< > $@
> -	./mk_dsdt --maxcpu $*  >> $@
> +	awk 'NR > 1 {print s} {s=$$0}' $< > $@.tmp
> +	sed -i 's/AmlCode/dsdt_$*cpu/g' $@.tmp
> +	./mk_dsdt --maxcpu $*  >> $@.tmp
> +	$(call move-if-changed,$@.tmp $@)
>  
> -$(filter dsdt_%.c,$(C_SRC)): %.c: iasl %.asl
> -	iasl -vs -p $* -tc $*.asl
> -	sed -e 's/AmlCode/$*/g' $*.hex >$@
> -	echo "int $*_len=sizeof($*);" >>$@
> -	rm -f $*.aml $*.hex
> +$(filter dsdt_%.c,$(C_SRC)): %.c: iasl python %.asl

As you need to touch this anyway, please adjust it to match
common style: The input file should come first in the list of
dependencies, allowing you ...

> +	cpp -P $*.asl > $*.asl.i.orig

... use $< here (and further down where applicable) in favor of $*.

> +	python ../tools/acpi_extract_preprocess.py $*.asl.i.orig > $*.asl.i

Please be consistent in whether you put a blank after ">" and ">>".

> +	iasl -vs -l -tc -p $* $*.asl.i
> +	python ../tools/acpi_extract.py $*.lst > $@.tmp
> +	echo "int $*_len=sizeof($*);" >>$@.tmp
> +	if grep -q "$*_aml_ej0_name" $@.tmp; then echo "int $*_aml_ej0_name_len=sizeof($*_aml_ej0_name);" >>$@.tmp; fi
> +	if grep -q "$*_aml_adr_dword" $@.tmp; then echo "int $*_aml_adr_dword_len=sizeof($*_aml_adr_dword);" >>$@.tmp;fi

Missing blank before "fi".

> +python:
> +	@echo
> +	@echo "python is needed"
> +	@echo
> +	@exit 1

What is this good for? For one, the tools build already requires
Python. And then such a dependency would belong into the
configure scripts, not here.

> --- a/tools/firmware/hvmloader/acpi/build.c
> +++ b/tools/firmware/hvmloader/acpi/build.c

There are various coding style issues in the changes to this file.
Please make sure you match the style found elsewhere in here.

> @@ -30,6 +30,9 @@
>  #define align16(sz)        (((sz) + 15) & ~15)
>  #define fixed_strcpy(d, s) strncpy((d), (s), sizeof(d))
>  
> +
> +#define PCI_RMV_BASE 0xae0c
> +
>  extern struct acpi_20_rsdp Rsdp;
>  extern struct acpi_20_rsdt Rsdt;
>  extern struct acpi_20_xsdt Xsdt;
> @@ -404,6 +407,7 @@ void acpi_build_tables(struct acpi_config *config, unsigned int physical)
>      unsigned char       *dsdt;
>      unsigned long        secondary_tables[ACPI_MAX_SECONDARY_TABLES];
>      int                  nr_secondaries, i;
> +    unsigned int rmvc_pcrm = 0;

Pointless initializer. You'd be better off moving the declaration to
the first use point anyway (and then it can have a proper initializer
right away).

> @@ -438,9 +442,27 @@ void acpi_build_tables(struct acpi_config *config, unsigned int physical)
>          dsdt = mem_alloc(config->dsdt_anycpu_len, 16);
>          if (!dsdt) goto oom;
>          memcpy(dsdt, config->dsdt_anycpu, config->dsdt_anycpu_len);
> -        nr_processor_objects = HVM_MAX_VCPUS;

The movement to this assignment is clearly wrong, as it now
overwrites the different value stored when using the <= 15 CPUs
path.

This also raises the question of why you do the adjustment below
only in the >= 16 CPUs code path.

I also don't see how this adjustment is in line with mk_dsdt.c's
handling of the qemu-traditional case. Or is that building on
SeaBIOS only ever being used with upstream qemu?

> +        if(config->aml_adr_dword_len && config->aml_ej0_name_len &&
> +            (config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]) == config->aml_ej0_name_len/sizeof(config->aml_ej0_name[0])))
> +        {
> +            rmvc_pcrm = inl(PCI_RMV_BASE); 
> +            printf("rmvc_pcrm is %x\n", rmvc_pcrm);
> +            for(i = 0;  i < config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]); i ++)
> +            {
> +                /* Slot is in byte 2 in _ADR */
> +                unsigned char slot = dsdt[config->aml_adr_dword[i] + 2] & 0x1F;
> +                /* Sanity check */
> +                if (memcmp(dsdt + config->aml_ej0_name[i], "_EJ0", 4)) {
> +                    goto oom;

A memcmp() failure should result in a meaningful error message;
definitely not "out of memory".

> +                }
> +                if (!(rmvc_pcrm & (0x1 << slot))) {
> +                    memcpy(dsdt + config->aml_ej0_name[i], "EJ0_", 4);
> +                }
> +            }
> +        }

> --- a/tools/firmware/hvmloader/ovmf.c
> +++ b/tools/firmware/hvmloader/ovmf.c
> @@ -79,7 +79,11 @@ static void ovmf_acpi_build_tables(void)
>          .dsdt_anycpu = dsdt_anycpu,
>          .dsdt_anycpu_len = dsdt_anycpu_len,
>          .dsdt_15cpu = NULL, 
> -        .dsdt_15cpu_len = 0
> +        .dsdt_15cpu_len = 0,
> +        .aml_ej0_name = NULL,
> +        .aml_adr_dword = NULL,
> +        .aml_ej0_name_len = 0,
> +        .aml_adr_dword_len = 0,

I don't see why you're adding these.

> --- a/tools/firmware/hvmloader/rombios.c
> +++ b/tools/firmware/hvmloader/rombios.c
> @@ -179,6 +179,10 @@ static void rombios_acpi_build_tables(void)
>          .dsdt_anycpu_len = dsdt_anycpu_len,
>          .dsdt_15cpu = dsdt_15cpu,
>          .dsdt_15cpu_len = dsdt_15cpu_len,
> +        .aml_ej0_name = NULL,
> +        .aml_adr_dword = NULL,
> +        .aml_ej0_name_len = 0,
> +        .aml_adr_dword_len = 0,

Same here.

Jan

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [Xen-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
  2013-10-22  8:06               ` [Qemu-devel] [Xen-devel] " Jan Beulich
  2013-10-24 12:17                 ` [Qemu-devel] " Gonglei (Arei)
@ 2013-10-24 12:17                 ` Gonglei (Arei)
  2013-10-24 12:57                   ` Fabio Fantoni
                                     ` (3 more replies)
  2013-10-28  7:14                 ` Gonglei (Arei)
  2013-10-28  7:14                 ` [Qemu-devel] [Xen-devel] " Gonglei (Arei)
  3 siblings, 4 replies; 38+ messages in thread
From: Gonglei (Arei) @ 2013-10-24 12:17 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Yanqiangjun, Ian Campbell, Hanweidong (Randy),
	Markus Armbruster, Stefano Stabellini, Luonengjun, qemu-devel,
	xen-devel, Fabio Fantoni, anthony.perard, Gaowei (UVP),
	Huangweidong (Hardware)

[-- Attachment #1: Type: text/plain, Size: 25259 bytes --]


> -----Original Message-----
> From: Jan Beulich [mailto:JBeulich@suse.com]
> Sent: Tuesday, October 22, 2013 4:06 PM
> To: Gonglei (Arei)
> Cc: anthony.perard@citrix.com; Ian Campbell; Stefano Stabellini; Gaowei (UVP);
> Hanweidong (Randy); Huangweidong (Hardware); Luonengjun; Yanqiangjun;
> xen-devel@lists.xen.org; Fabio Fantoni; qemu-devel@nongnu.org; Markus
> Armbruster
> Subject: RE: [Qemu-devel] [Xen-devel] Hvmloader: Modify ACPI to only supply
> _EJ0 methods for PCIslots that support hotplug by runtime patching
> 
> >>> On 22.10.13 at 06:08, "Gonglei (Arei)" <arei.gonglei@huawei.com> wrote:
> > Hi, guys. The new patch has been modified based on the principles you
> > suggested, thank you so much.
> > Last time I test the patch based on the codes of 4.3.0.
> > This time, I found that the system based on the codes of trunk causes the VM
> > reboot again and again, which I have not found out the reason.
> > So i can not test the patch based on the codes of trunk (details in
> > EJ0_ACPI_PCI_Hotplug.patch)..
> 
> I'm afraid we will need you to figure out that problem first, and
> then do the verification on -unstable. Even if the code shouldn't
> be that different from 4.3, we still don't want to apply completely
> untested stuff.

Hi, Jan. We found that the reason that we used a wrong seabios PATH, and the hvmloader can't load the bios.bin.
So the VM restart again and again after we start it. That's our fault.

Now I test the patch based on the codes of trunk, which works well.
The patch has been modified after your suggestion.
The patch works well with upstream qemu and doesn't affect the system with traditional qemu.

> 
> 
> > --- a/tools/firmware/hvmloader/ovmf.c
> > +++ b/tools/firmware/hvmloader/ovmf.c
> > @@ -79,7 +79,11 @@ static void ovmf_acpi_build_tables(void)
> >          .dsdt_anycpu = dsdt_anycpu,
> >          .dsdt_anycpu_len = dsdt_anycpu_len,
> >          .dsdt_15cpu = NULL,
> > -        .dsdt_15cpu_len = 0
> > +        .dsdt_15cpu_len = 0,
> > +        .aml_ej0_name = NULL,
> > +        .aml_adr_dword = NULL,
> > +        .aml_ej0_name_len = 0,
> > +        .aml_adr_dword_len = 0,
> 
> I don't see why you're adding these.
> 
Insurance purposes is that just initialize the struct.

Signed-off-by: Gaowei <gao.gaowei@huawei.com>
Signed-off-by: gonglei <arei.gonglei@huawei.com>
---
 tools/firmware/hvmloader/acpi/Makefile             |  37 ++-
 tools/firmware/hvmloader/acpi/acpi2_0.h            |   4 +
 tools/firmware/hvmloader/acpi/build.c              |  21 +-
 tools/firmware/hvmloader/acpi/dsdt.asl             |   1 +
 tools/firmware/hvmloader/acpi/mk_dsdt.c            |   2 +
 tools/firmware/hvmloader/ovmf.c                    |   6 +-
 tools/firmware/hvmloader/rombios.c                 |   4 +
 tools/firmware/hvmloader/seabios.c                 |   8 +
 tools/firmware/hvmloader/tools/acpi_extract.py     | 308 +++++++++++++++++++++
 .../hvmloader/tools/acpi_extract_preprocess.py     |  41 +++
 10 files changed, 419 insertions(+), 13 deletions(-)
 create mode 100644 tools/firmware/hvmloader/tools/acpi_extract.py
 create mode 100644 tools/firmware/hvmloader/tools/acpi_extract_preprocess.py

diff --git a/tools/firmware/hvmloader/acpi/Makefile b/tools/firmware/hvmloader/acpi/Makefile
index 2c50851..b96e058 100644
--- a/tools/firmware/hvmloader/acpi/Makefile
+++ b/tools/firmware/hvmloader/acpi/Makefile
@@ -24,30 +24,45 @@ OBJS  = $(patsubst %.c,%.o,$(C_SRC))
 CFLAGS += $(CFLAGS_xeninclude)
 
 vpath iasl $(PATH)
+
+.DELETE_ON_ERROR: $(filter dsdt_%.c,$(C_SRC))
+
 all: acpi.a
 
 ssdt_s3.h ssdt_s4.h ssdt_pm.h ssdt_tpm.h: %.h: %.asl iasl
 	iasl -vs -p $* -tc $<
-	sed -e 's/AmlCode/$*/g' $*.hex >$@
+	sed -e 's/AmlCode/$*/g' $*.hex > $@.tmp
+	$(call move-if-changed,$@.tmp $@)
 	rm -f $*.hex $*.aml
 
 mk_dsdt: mk_dsdt.c
 	$(HOSTCC) $(HOSTCFLAGS) $(CFLAGS_xeninclude) -o $@ mk_dsdt.c
 
 dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
-	awk 'NR > 1 {print s} {s=$$0}' $< > $@
-	./mk_dsdt --dm-version qemu-xen >> $@
+	awk 'NR > 1 {print s} {s=$$0}' $< > $@.tmp
+	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@.tmp
+	./mk_dsdt --dm-version qemu-xen >> $@.tmp
+	sed -i 's/aml_ej0_name/dsdt_anycpu_qemu_xen_aml_ej0_name/g' $@.tmp
+	sed -i 's/aml_adr_dword/dsdt_anycpu_qemu_xen_aml_adr_dword/g' $@.tmp
+	$(call move-if-changed,$@.tmp $@)
 
 # NB. awk invocation is a portable alternative to 'head -n -1'
 dsdt_%cpu.asl: dsdt.asl mk_dsdt
-	awk 'NR > 1 {print s} {s=$$0}' $< > $@
-	./mk_dsdt --maxcpu $*  >> $@
+	awk 'NR > 1 {print s} {s=$$0}' $< > $@.tmp
+	sed -i 's/AmlCode/dsdt_$*cpu/g' $@.tmp
+	./mk_dsdt --maxcpu $*  >> $@.tmp
+	$(call move-if-changed,$@.tmp $@)
 
-$(filter dsdt_%.c,$(C_SRC)): %.c: iasl %.asl
-	iasl -vs -p $* -tc $*.asl
-	sed -e 's/AmlCode/$*/g' $*.hex >$@
-	echo "int $*_len=sizeof($*);" >>$@
-	rm -f $*.aml $*.hex
+$(filter dsdt_%.c,$(C_SRC)): %.c: %.asl iasl
+	cpp -P $< > $<.i.orig
+	$(PYTHON) ../tools/acpi_extract_preprocess.py $<.i.orig > $<.i
+	iasl -vs -l -tc -p $* $<.i
+	$(PYTHON) ../tools/acpi_extract.py $*.lst > $@.tmp
+	echo "int $*_len=sizeof($*);" >> $@.tmp
+	if grep -q "$*_aml_ej0_name" $@.tmp; then echo "int $*_aml_ej0_name_len=sizeof($*_aml_ej0_name);" >> $@.tmp; fi
+	if grep -q "$*_aml_adr_dword" $@.tmp; then echo "int $*_aml_adr_dword_len=sizeof($*_aml_adr_dword);" >> $@.tmp; fi
+	$(call move-if-changed,$@.tmp $@)
+	rm -f $*.aml $*.hex $*.asl.i.orig $*.asl.i $*.lst
 
 iasl:
 	@echo
@@ -64,7 +79,7 @@ acpi.a: $(OBJS)
 
 clean:
 	rm -rf *.a *.o $(IASL_VER) $(IASL_VER).tar.gz $(DEPS)
-	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl
+	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl *.asl.i *.asl.i.orig *.lst *.tmp
 
 install: all
 
diff --git a/tools/firmware/hvmloader/acpi/acpi2_0.h b/tools/firmware/hvmloader/acpi/acpi2_0.h
index 7b22d80..4ba3957 100644
--- a/tools/firmware/hvmloader/acpi/acpi2_0.h
+++ b/tools/firmware/hvmloader/acpi/acpi2_0.h
@@ -396,6 +396,10 @@ struct acpi_config {
     int dsdt_anycpu_len;
     unsigned char *dsdt_15cpu;
     int dsdt_15cpu_len;
+    unsigned short *aml_ej0_name;
+    unsigned short *aml_adr_dword;
+    int aml_ej0_name_len;
+    int aml_adr_dword_len;
 };
 
 void acpi_build_tables(struct acpi_config *config, unsigned int physical);
diff --git a/tools/firmware/hvmloader/acpi/build.c b/tools/firmware/hvmloader/acpi/build.c
index f1dd3f0..7eb21d3 100644
--- a/tools/firmware/hvmloader/acpi/build.c
+++ b/tools/firmware/hvmloader/acpi/build.c
@@ -29,6 +29,7 @@
 
 #define align16(sz)        (((sz) + 15) & ~15)
 #define fixed_strcpy(d, s) strncpy((d), (s), sizeof(d))
+#define PCI_RMV_BASE 0xae0c
 
 extern struct acpi_20_rsdp Rsdp;
 extern struct acpi_20_rsdt Rsdt;
@@ -404,6 +405,7 @@ void acpi_build_tables(struct acpi_config *config, unsigned int physical)
     unsigned char       *dsdt;
     unsigned long        secondary_tables[ACPI_MAX_SECONDARY_TABLES];
     int                  nr_secondaries, i;
+    unsigned int rmvc_pcrm = 0;
 
     /* Allocate and initialise the acpi info area. */
     mem_hole_populate_ram(ACPI_INFO_PHYSICAL_ADDRESS >> PAGE_SHIFT, 1);
@@ -440,7 +442,24 @@ void acpi_build_tables(struct acpi_config *config, unsigned int physical)
         memcpy(dsdt, config->dsdt_anycpu, config->dsdt_anycpu_len);
         nr_processor_objects = HVM_MAX_VCPUS;
     }
-
+    if(config->aml_adr_dword_len && config->aml_ej0_name_len &&
+        (config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]) == config->aml_ej0_name_len/sizeof(config->aml_ej0_name[0])))
+    {
+        rmvc_pcrm = inl(PCI_RMV_BASE); 
+        for(i = 0;  i < config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]); i ++)
+        {
+            /* Slot is in byte 2 in _ADR */
+            unsigned char slot = dsdt[config->aml_adr_dword[i] + 2] & 0x1F;
+            /* Sanity check */
+            if (memcmp(dsdt + config->aml_ej0_name[i], "_EJ0", 4)) {
+                printf("Method '_EJ0' can not be found for pci slot %d\n", slot);
+                return;
+            }
+            if (!(rmvc_pcrm & (0x1 << slot))) {
+                memcpy(dsdt + config->aml_ej0_name[i], "EJ0_", 4);
+            }
+        }
+    }
     /*
      * N.B. ACPI 1.0 operating systems may not handle FADT with revision 2
      * or above properly, notably Windows 2000, which tries to copy FADT
diff --git a/tools/firmware/hvmloader/acpi/dsdt.asl b/tools/firmware/hvmloader/acpi/dsdt.asl
index 247a8ad..1e7695b 100644
--- a/tools/firmware/hvmloader/acpi/dsdt.asl
+++ b/tools/firmware/hvmloader/acpi/dsdt.asl
@@ -16,6 +16,7 @@
  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  * Place - Suite 330, Boston, MA 02111-1307 USA.
  */
+ACPI_EXTRACT_ALL_CODE AmlCode
 
 DefinitionBlock ("DSDT.aml", "DSDT", 2, "Xen", "HVM", 0)
 {
diff --git a/tools/firmware/hvmloader/acpi/mk_dsdt.c b/tools/firmware/hvmloader/acpi/mk_dsdt.c
index 996f30b..4180801 100644
--- a/tools/firmware/hvmloader/acpi/mk_dsdt.c
+++ b/tools/firmware/hvmloader/acpi/mk_dsdt.c
@@ -368,7 +368,9 @@ int main(int argc, char **argv)
         /* hotplug_slot */
         for (slot = 1; slot <= 31; slot++) {
             push_block("Device", "S%i", slot); {
+                printf("ACPI_EXTRACT_NAME_DWORD_CONST aml_adr_dword\n");
                 stmt("Name", "_ADR, %#06x0000", slot);
+                printf("ACPI_EXTRACT_METHOD_STRING aml_ej0_name\n");
                 push_block("Method", "_EJ0,1"); {
                     stmt("Store", "ShiftLeft(1, %#06x), B0EJ", slot);
                     stmt("Return", "0x0");
diff --git a/tools/firmware/hvmloader/ovmf.c b/tools/firmware/hvmloader/ovmf.c
index ee4cbbf..27ff0b5 100644
--- a/tools/firmware/hvmloader/ovmf.c
+++ b/tools/firmware/hvmloader/ovmf.c
@@ -79,7 +79,11 @@ static void ovmf_acpi_build_tables(void)
         .dsdt_anycpu = dsdt_anycpu,
         .dsdt_anycpu_len = dsdt_anycpu_len,
         .dsdt_15cpu = NULL, 
-        .dsdt_15cpu_len = 0
+        .dsdt_15cpu_len = 0,
+        .aml_ej0_name = NULL,
+        .aml_adr_dword = NULL,
+        .aml_ej0_name_len = 0,
+        .aml_adr_dword_len = 0,
     };
 
     acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
diff --git a/tools/firmware/hvmloader/rombios.c b/tools/firmware/hvmloader/rombios.c
index 810bd24..803c9fa 100644
--- a/tools/firmware/hvmloader/rombios.c
+++ b/tools/firmware/hvmloader/rombios.c
@@ -179,6 +179,10 @@ static void rombios_acpi_build_tables(void)
         .dsdt_anycpu_len = dsdt_anycpu_len,
         .dsdt_15cpu = dsdt_15cpu,
         .dsdt_15cpu_len = dsdt_15cpu_len,
+        .aml_ej0_name = NULL,
+        .aml_adr_dword = NULL,
+        .aml_ej0_name_len = 0,
+        .aml_adr_dword_len = 0,
     };
 
     acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
diff --git a/tools/firmware/hvmloader/seabios.c b/tools/firmware/hvmloader/seabios.c
index dd7dfbe..ca01d27 100644
--- a/tools/firmware/hvmloader/seabios.c
+++ b/tools/firmware/hvmloader/seabios.c
@@ -33,6 +33,10 @@
 
 extern unsigned char dsdt_anycpu_qemu_xen[];
 extern int dsdt_anycpu_qemu_xen_len;
+extern unsigned short dsdt_anycpu_qemu_xen_aml_ej0_name[];
+extern unsigned short dsdt_anycpu_qemu_xen_aml_adr_dword[];
+extern int dsdt_anycpu_qemu_xen_aml_ej0_name_len;
+extern int dsdt_anycpu_qemu_xen_aml_adr_dword_len;
 
 struct seabios_info {
     char signature[14]; /* XenHVMSeaBIOS\0 */
@@ -99,6 +103,10 @@ static void seabios_acpi_build_tables(void)
         .dsdt_anycpu_len = dsdt_anycpu_qemu_xen_len,
         .dsdt_15cpu = NULL,
         .dsdt_15cpu_len = 0,
+        .aml_ej0_name = dsdt_anycpu_qemu_xen_aml_ej0_name,
+        .aml_adr_dword = dsdt_anycpu_qemu_xen_aml_adr_dword,
+        .aml_ej0_name_len = dsdt_anycpu_qemu_xen_aml_ej0_name_len,
+        .aml_adr_dword_len = dsdt_anycpu_qemu_xen_aml_adr_dword_len,
     };
 
     acpi_build_tables(&config, rsdp);
diff --git a/tools/firmware/hvmloader/tools/acpi_extract.py b/tools/firmware/hvmloader/tools/acpi_extract.py
new file mode 100644
index 0000000..4fa51f7
--- /dev/null
+++ b/tools/firmware/hvmloader/tools/acpi_extract.py
@@ -0,0 +1,308 @@
+#!/usr/bin/python
+# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+# Process mixed ASL/AML listing (.lst file) produced by iasl -l
+# Locate and execute ACPI_EXTRACT directives, output offset info
+# 
+# Documentation of ACPI_EXTRACT_* directive tags:
+# 
+# These directive tags output offset information from AML for BIOS runtime
+# table generation.
+# Each directive is of the form:
+# ACPI_EXTRACT_<TYPE> <array_name> <Operator> (...)
+# and causes the extractor to create an array
+# named <array_name> with offset, in the generated AML,
+# of an object of a given type in the following <Operator>.
+# 
+# A directive must fit on a single code line.
+# 
+# Object type in AML is verified, a mismatch causes a build failure.
+# 
+# Directives and operators currently supported are:
+# ACPI_EXTRACT_NAME_DWORD_CONST - extract a Dword Const object from Name()
+# ACPI_EXTRACT_NAME_WORD_CONST - extract a Word Const object from Name()
+# ACPI_EXTRACT_NAME_BYTE_CONST - extract a Byte Const object from Name()
+# ACPI_EXTRACT_METHOD_STRING - extract a NameString from Method()
+# ACPI_EXTRACT_NAME_STRING - extract a NameString from Name()
+# ACPI_EXTRACT_PROCESSOR_START - start of Processor() block
+# ACPI_EXTRACT_PROCESSOR_STRING - extract a NameString from Processor()
+# ACPI_EXTRACT_PROCESSOR_END - offset at last byte of Processor() + 1
+# ACPI_EXTRACT_PKG_START - start of Package block
+#
+# ACPI_EXTRACT_ALL_CODE - create an array storing the generated AML bytecode
+# 
+# ACPI_EXTRACT is not allowed anywhere else in code, except in comments.
+
+import re;
+import sys;
+import fileinput;
+
+aml = []
+asl = []
+output = {}
+debug = ""
+
+class asl_line:
+    line = None
+    lineno = None
+    aml_offset = None
+
+def die(diag):
+    sys.stderr.write("Error: %s; %s\n" % (diag, debug))
+    sys.exit(1)
+    
+#Store an ASL command, matching AML offset, and input line (for debugging)
+def add_asl(lineno, line):
+    l = asl_line()
+    l.line = line
+    l.lineno = lineno
+    l.aml_offset = len(aml)
+    asl.append(l)
+
+#Store an AML byte sequence
+#Verify that offset output by iasl matches # of bytes so far
+def add_aml(offset, line):
+    o = int(offset, 16);
+    # Sanity check: offset must match size of code so far
+    if (o != len(aml)):
+        die("Offset 0x%x != 0x%x" % (o, len(aml)))
+    # Strip any trailing dots and ASCII dump after "
+    line = re.sub(r'\s*\.*\s*".*$',"", line)
+    # Strip traling whitespace
+    line = re.sub(r'\s+$',"", line)
+    # Strip leading whitespace
+    line = re.sub(r'^\s+',"", line)
+    # Split on whitespace
+    code = re.split(r'\s+', line)
+    for c in code:
+        # Require a legal hex number, two digits
+        if (not(re.search(r'^[0-9A-Fa-f][0-9A-Fa-f]$', c))):
+            die("Unexpected octet %s" % c);
+        aml.append(int(c, 16));
+
+# Process aml bytecode array, decoding AML
+def aml_pkglen_bytes(offset):
+    # PkgLength can be multibyte. Bits 8-7 give the # of extra bytes.
+    pkglenbytes = aml[offset] >> 6;
+    return pkglenbytes + 1
+
+def aml_pkglen(offset):
+    pkgstart = offset
+    pkglenbytes = aml_pkglen_bytes(offset)
+    pkglen = aml[offset] & 0x3F
+    # If multibyte, first nibble only uses bits 0-3
+    if ((pkglenbytes > 0) and (pkglen & 0x30)):
+        die("PkgLen bytes 0x%x but first nibble 0x%x expected 0x0X" %
+            (pkglen, pkglen))
+    offset += 1
+    pkglenbytes -= 1
+    for i in range(pkglenbytes):
+        pkglen |= aml[offset + i] << (i * 8 + 4)
+    if (len(aml) < pkgstart + pkglen):
+        die("PckgLen 0x%x at offset 0x%x exceeds AML size 0x%x" %
+            (pkglen, offset, len(aml)))
+    return pkglen
+
+# Given method offset, find its NameString offset
+def aml_method_string(offset):
+    #0x14 MethodOp PkgLength NameString MethodFlags TermList
+    if (aml[offset] != 0x14):
+        die( "Method offset 0x%x: expected 0x14 actual 0x%x" %
+             (offset, aml[offset]));
+    offset += 1;
+    pkglenbytes = aml_pkglen_bytes(offset)
+    offset += pkglenbytes;
+    return offset;
+
+# Given name offset, find its NameString offset
+def aml_name_string(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x08):
+        die( "Name offset 0x%x: expected 0x08 actual 0x%x" %
+             (offset, aml[offset]));
+    offset += 1
+    # Block Name Modifier. Skip it.
+    if (aml[offset] == 0x5c or aml[offset] == 0x5e):
+        offset += 1
+    return offset;
+
+# Given data offset, find dword const offset
+def aml_data_dword_const(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x0C):
+        die( "Name offset 0x%x: expected 0x0C actual 0x%x" %
+             (offset, aml[offset]));
+    return offset + 1;
+
+# Given data offset, find word const offset
+def aml_data_word_const(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x0B):
+        die( "Name offset 0x%x: expected 0x0B actual 0x%x" %
+             (offset, aml[offset]));
+    return offset + 1;
+
+# Given data offset, find byte const offset
+def aml_data_byte_const(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x0A):
+        die( "Name offset 0x%x: expected 0x0A actual 0x%x" %
+             (offset, aml[offset]));
+    return offset + 1;
+
+# Given name offset, find dword const offset
+def aml_name_dword_const(offset):
+    return aml_data_dword_const(aml_name_string(offset) + 4)
+
+# Given name offset, find word const offset
+def aml_name_word_const(offset):
+    return aml_data_word_const(aml_name_string(offset) + 4)
+
+# Given name offset, find byte const offset
+def aml_name_byte_const(offset):
+    return aml_data_byte_const(aml_name_string(offset) + 4)
+
+def aml_processor_start(offset):
+    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
+    if ((aml[offset] != 0x5B) or (aml[offset + 1] != 0x83)):
+        die( "Name offset 0x%x: expected 0x5B 0x83 actual 0x%x 0x%x" %
+             (offset, aml[offset], aml[offset + 1]));
+    return offset
+
+def aml_processor_string(offset):
+    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
+    start = aml_processor_start(offset)
+    offset += 2
+    pkglenbytes = aml_pkglen_bytes(offset)
+    offset += pkglenbytes
+    return offset
+
+def aml_processor_end(offset):
+    start = aml_processor_start(offset)
+    offset += 2
+    pkglenbytes = aml_pkglen_bytes(offset)
+    pkglen = aml_pkglen(offset)
+    return offset + pkglen
+
+def aml_package_start(offset):
+    offset = aml_name_string(offset) + 4
+    # 0x12 PkgLength NumElements PackageElementList
+    if (aml[offset] != 0x12):
+        die( "Name offset 0x%x: expected 0x12 actual 0x%x" %
+             (offset, aml[offset]));
+    offset += 1
+    return offset + aml_pkglen_bytes(offset) + 1
+
+lineno = 0
+for line in fileinput.input():
+    # Strip trailing newline
+    line = line.rstrip();
+    # line number and debug string to output in case of errors
+    lineno = lineno + 1
+    debug = "input line %d: %s" % (lineno, line)
+    #ASL listing: space, then line#, then ...., then code
+    pasl = re.compile('^\s+([0-9]+)\.\.\.\.\s*')
+    m = pasl.search(line)
+    if (m):
+        add_asl(lineno, pasl.sub("", line));
+    # AML listing: offset in hex, then ...., then code
+    paml = re.compile('^([0-9A-Fa-f]+)\.\.\.\.\s*')
+    m = paml.search(line)
+    if (m):
+        add_aml(m.group(1), paml.sub("", line))
+
+# Now go over code
+# Track AML offset of a previous non-empty ASL command
+prev_aml_offset = -1
+for i in range(len(asl)):
+    debug = "input line %d: %s" % (asl[i].lineno, asl[i].line)
+
+    l = asl[i].line
+
+    # skip if not an extract directive
+    a = len(re.findall(r'ACPI_EXTRACT', l))
+    if (not a):
+        # If not empty, store AML offset. Will be used for sanity checks
+        # IASL seems to put {}. at random places in the listing.
+        # Ignore any non-words for the purpose of this test.
+        m = re.search(r'\w+', l)
+        if (m):
+                prev_aml_offset = asl[i].aml_offset
+        continue
+
+    if (a > 1):
+        die("Expected at most one ACPI_EXTRACT per line, actual %d" % a)
+
+    mext = re.search(r'''
+                      ^\s* # leading whitespace
+                      /\*\s* # start C comment
+                      (ACPI_EXTRACT_\w+) # directive: group(1)
+                      \s+ # whitspace separates directive from array name
+                      (\w+) # array name: group(2)
+                      \s*\*/ # end of C comment
+                      \s*$ # trailing whitespace
+                      ''', l, re.VERBOSE)
+    if (not mext):
+        die("Stray ACPI_EXTRACT in input")
+
+    # previous command must have produced some AML,
+    # otherwise we are in a middle of a block
+    if (prev_aml_offset == asl[i].aml_offset):
+        die("ACPI_EXTRACT directive in the middle of a block")
+
+    directive = mext.group(1)
+    array = mext.group(2)
+    offset = asl[i].aml_offset
+
+    if (directive == "ACPI_EXTRACT_ALL_CODE"):
+        if array in output:
+            die("%s directive used more than once" % directive)
+        output[array] = aml
+        continue
+    if (directive == "ACPI_EXTRACT_NAME_DWORD_CONST"):
+        offset = aml_name_dword_const(offset)
+    elif (directive == "ACPI_EXTRACT_NAME_WORD_CONST"):
+        offset = aml_name_word_const(offset)
+    elif (directive == "ACPI_EXTRACT_NAME_BYTE_CONST"):
+        offset = aml_name_byte_const(offset)
+    elif (directive == "ACPI_EXTRACT_NAME_STRING"):
+        offset = aml_name_string(offset)
+    elif (directive == "ACPI_EXTRACT_METHOD_STRING"):
+        offset = aml_method_string(offset)
+    elif (directive == "ACPI_EXTRACT_PROCESSOR_START"):
+        offset = aml_processor_start(offset)
+    elif (directive == "ACPI_EXTRACT_PROCESSOR_STRING"):
+        offset = aml_processor_string(offset)
+    elif (directive == "ACPI_EXTRACT_PROCESSOR_END"):
+        offset = aml_processor_end(offset)
+    elif (directive == "ACPI_EXTRACT_PKG_START"):
+        offset = aml_package_start(offset)
+    else:
+        die("Unsupported directive %s" % directive)
+
+    if array not in output:
+        output[array] = []
+    output[array].append(offset)
+
+debug = "at end of file"
+
+def get_value_type(maxvalue):
+    #Use type large enough to fit the table
+    if (maxvalue >= 0x10000):
+            return "int"
+    elif (maxvalue >= 0x100):
+            return "short"
+    else:
+            return "char"
+
+# Pretty print output
+for array in output.keys():
+    otype = get_value_type(max(output[array]))
+    odata = []
+    for value in output[array]:
+        odata.append("0x%x" % value)
+    sys.stdout.write("unsigned %s %s[] = {\n" % (otype, array))
+    sys.stdout.write(",\n".join(odata))
+    sys.stdout.write('\n};\n');
diff --git a/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py b/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py
new file mode 100644
index 0000000..4ae364e
--- /dev/null
+++ b/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py
@@ -0,0 +1,41 @@
+#!/usr/bin/python
+# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+# Read a preprocessed ASL listing and put each ACPI_EXTRACT
+# directive in a comment, to make iasl skip it.
+# We also put each directive on a new line, the machinery
+# in tools/acpi_extract.py requires this.
+
+import re;
+import sys;
+import fileinput;
+
+def die(diag):
+    sys.stderr.write("Error: %s\n" % (diag))
+    sys.exit(1)
+
+# Note: () around pattern make split return matched string as part of list
+psplit = re.compile(r''' (
+                          \b # At word boundary
+                          ACPI_EXTRACT_\w+ # directive
+                          \s+ # some whitespace
+                          \w+ # array name
+                         )''', re.VERBOSE);
+
+lineno = 0
+for line in fileinput.input():
+    # line number and debug string to output in case of errors
+    lineno = lineno + 1
+    debug = "input line %d: %s" % (lineno, line.rstrip())
+
+    s = psplit.split(line);
+    # The way split works, each odd item is the matching ACPI_EXTRACT directive.
+    # Put each in a comment, and on a line by itself.
+    for i in range(len(s)):
+        if (i % 2):
+            sys.stdout.write("\n/* %s */\n" % s[i])
+        else:
+            sys.stdout.write(s[i])
+
-- 
1.8.3.4

Best regards,
-Gonglei


[-- Attachment #2: 0001-Hvmloader-Modify-ACPI-to-only-supply-_EJ0-methods-fo.patch --]
[-- Type: application/octet-stream, Size: 23408 bytes --]

From 1a23acffa55e5ed4c1df860bdacd4e485d74861f Mon Sep 17 00:00:00 2001
From: Gaowei <gao.gaowei@huawei.com>
Date: Thu, 24 Oct 2013 17:19:16 +0800
Subject: [PATCH] Hvmloader: Modify ACPI to only supply _EJ0 methods for
 PCIslots that support hotplug by runtime patching

In Xen platform, after using upstream qemu, the all of pci devices will show hotplug in the windows guest.
In this situation, the windows guest may occur blue screen when VM' user click the icon of VGA card for trying unplug VGA card.
However, we don't hope VM's user can do such dangerous operation, and showing all pci devices inside the guest OS is unfriendly.
This is done by runtime patching:
  - Rename _EJ0 methods for PCI slots in DSDT to EJ0_:note that this has the same checksum, but is ignored by OSPM.
  - At compile time, look for these methods in ASL source,find the matching AML, and store the offsets of these methods in a table named aml_ej0_data.
  - At run time, go over aml_ej0_data, check which slots not support hotplug and patch the ACPI table, replacing _EJ0 with EJ0_.

Signed-off-by: Gaowei <gao.gaowei@huawei.com>
Signed-off-by: gonglei <arei.gonglei@huawei.com>
---
 tools/firmware/hvmloader/acpi/Makefile             |  37 ++-
 tools/firmware/hvmloader/acpi/acpi2_0.h            |   4 +
 tools/firmware/hvmloader/acpi/build.c              |  21 +-
 tools/firmware/hvmloader/acpi/dsdt.asl             |   1 +
 tools/firmware/hvmloader/acpi/mk_dsdt.c            |   2 +
 tools/firmware/hvmloader/ovmf.c                    |   6 +-
 tools/firmware/hvmloader/rombios.c                 |   4 +
 tools/firmware/hvmloader/seabios.c                 |   8 +
 tools/firmware/hvmloader/tools/acpi_extract.py     | 308 +++++++++++++++++++++
 .../hvmloader/tools/acpi_extract_preprocess.py     |  41 +++
 10 files changed, 419 insertions(+), 13 deletions(-)
 create mode 100644 tools/firmware/hvmloader/tools/acpi_extract.py
 create mode 100644 tools/firmware/hvmloader/tools/acpi_extract_preprocess.py

diff --git a/tools/firmware/hvmloader/acpi/Makefile b/tools/firmware/hvmloader/acpi/Makefile
index 2c50851..b96e058 100644
--- a/tools/firmware/hvmloader/acpi/Makefile
+++ b/tools/firmware/hvmloader/acpi/Makefile
@@ -24,30 +24,45 @@ OBJS  = $(patsubst %.c,%.o,$(C_SRC))
 CFLAGS += $(CFLAGS_xeninclude)
 
 vpath iasl $(PATH)
+
+.DELETE_ON_ERROR: $(filter dsdt_%.c,$(C_SRC))
+
 all: acpi.a
 
 ssdt_s3.h ssdt_s4.h ssdt_pm.h ssdt_tpm.h: %.h: %.asl iasl
 	iasl -vs -p $* -tc $<
-	sed -e 's/AmlCode/$*/g' $*.hex >$@
+	sed -e 's/AmlCode/$*/g' $*.hex > $@.tmp
+	$(call move-if-changed,$@.tmp $@)
 	rm -f $*.hex $*.aml
 
 mk_dsdt: mk_dsdt.c
 	$(HOSTCC) $(HOSTCFLAGS) $(CFLAGS_xeninclude) -o $@ mk_dsdt.c
 
 dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
-	awk 'NR > 1 {print s} {s=$$0}' $< > $@
-	./mk_dsdt --dm-version qemu-xen >> $@
+	awk 'NR > 1 {print s} {s=$$0}' $< > $@.tmp
+	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@.tmp
+	./mk_dsdt --dm-version qemu-xen >> $@.tmp
+	sed -i 's/aml_ej0_name/dsdt_anycpu_qemu_xen_aml_ej0_name/g' $@.tmp
+	sed -i 's/aml_adr_dword/dsdt_anycpu_qemu_xen_aml_adr_dword/g' $@.tmp
+	$(call move-if-changed,$@.tmp $@)
 
 # NB. awk invocation is a portable alternative to 'head -n -1'
 dsdt_%cpu.asl: dsdt.asl mk_dsdt
-	awk 'NR > 1 {print s} {s=$$0}' $< > $@
-	./mk_dsdt --maxcpu $*  >> $@
+	awk 'NR > 1 {print s} {s=$$0}' $< > $@.tmp
+	sed -i 's/AmlCode/dsdt_$*cpu/g' $@.tmp
+	./mk_dsdt --maxcpu $*  >> $@.tmp
+	$(call move-if-changed,$@.tmp $@)
 
-$(filter dsdt_%.c,$(C_SRC)): %.c: iasl %.asl
-	iasl -vs -p $* -tc $*.asl
-	sed -e 's/AmlCode/$*/g' $*.hex >$@
-	echo "int $*_len=sizeof($*);" >>$@
-	rm -f $*.aml $*.hex
+$(filter dsdt_%.c,$(C_SRC)): %.c: %.asl iasl
+	cpp -P $< > $<.i.orig
+	$(PYTHON) ../tools/acpi_extract_preprocess.py $<.i.orig > $<.i
+	iasl -vs -l -tc -p $* $<.i
+	$(PYTHON) ../tools/acpi_extract.py $*.lst > $@.tmp
+	echo "int $*_len=sizeof($*);" >> $@.tmp
+	if grep -q "$*_aml_ej0_name" $@.tmp; then echo "int $*_aml_ej0_name_len=sizeof($*_aml_ej0_name);" >> $@.tmp; fi
+	if grep -q "$*_aml_adr_dword" $@.tmp; then echo "int $*_aml_adr_dword_len=sizeof($*_aml_adr_dword);" >> $@.tmp; fi
+	$(call move-if-changed,$@.tmp $@)
+	rm -f $*.aml $*.hex $*.asl.i.orig $*.asl.i $*.lst
 
 iasl:
 	@echo
@@ -64,7 +79,7 @@ acpi.a: $(OBJS)
 
 clean:
 	rm -rf *.a *.o $(IASL_VER) $(IASL_VER).tar.gz $(DEPS)
-	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl
+	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl *.asl.i *.asl.i.orig *.lst *.tmp
 
 install: all
 
diff --git a/tools/firmware/hvmloader/acpi/acpi2_0.h b/tools/firmware/hvmloader/acpi/acpi2_0.h
index 7b22d80..4ba3957 100644
--- a/tools/firmware/hvmloader/acpi/acpi2_0.h
+++ b/tools/firmware/hvmloader/acpi/acpi2_0.h
@@ -396,6 +396,10 @@ struct acpi_config {
     int dsdt_anycpu_len;
     unsigned char *dsdt_15cpu;
     int dsdt_15cpu_len;
+    unsigned short *aml_ej0_name;
+    unsigned short *aml_adr_dword;
+    int aml_ej0_name_len;
+    int aml_adr_dword_len;
 };
 
 void acpi_build_tables(struct acpi_config *config, unsigned int physical);
diff --git a/tools/firmware/hvmloader/acpi/build.c b/tools/firmware/hvmloader/acpi/build.c
index f1dd3f0..7eb21d3 100644
--- a/tools/firmware/hvmloader/acpi/build.c
+++ b/tools/firmware/hvmloader/acpi/build.c
@@ -29,6 +29,7 @@
 
 #define align16(sz)        (((sz) + 15) & ~15)
 #define fixed_strcpy(d, s) strncpy((d), (s), sizeof(d))
+#define PCI_RMV_BASE 0xae0c
 
 extern struct acpi_20_rsdp Rsdp;
 extern struct acpi_20_rsdt Rsdt;
@@ -404,6 +405,7 @@ void acpi_build_tables(struct acpi_config *config, unsigned int physical)
     unsigned char       *dsdt;
     unsigned long        secondary_tables[ACPI_MAX_SECONDARY_TABLES];
     int                  nr_secondaries, i;
+    unsigned int rmvc_pcrm = 0;
 
     /* Allocate and initialise the acpi info area. */
     mem_hole_populate_ram(ACPI_INFO_PHYSICAL_ADDRESS >> PAGE_SHIFT, 1);
@@ -440,7 +442,24 @@ void acpi_build_tables(struct acpi_config *config, unsigned int physical)
         memcpy(dsdt, config->dsdt_anycpu, config->dsdt_anycpu_len);
         nr_processor_objects = HVM_MAX_VCPUS;
     }
-
+    if(config->aml_adr_dword_len && config->aml_ej0_name_len &&
+        (config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]) == config->aml_ej0_name_len/sizeof(config->aml_ej0_name[0])))
+    {
+        rmvc_pcrm = inl(PCI_RMV_BASE); 
+        for(i = 0;  i < config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]); i ++)
+        {
+            /* Slot is in byte 2 in _ADR */
+            unsigned char slot = dsdt[config->aml_adr_dword[i] + 2] & 0x1F;
+            /* Sanity check */
+            if (memcmp(dsdt + config->aml_ej0_name[i], "_EJ0", 4)) {
+                printf("Method '_EJ0' can not be found for pci slot %d\n", slot);
+                return;
+            }
+            if (!(rmvc_pcrm & (0x1 << slot))) {
+                memcpy(dsdt + config->aml_ej0_name[i], "EJ0_", 4);
+            }
+        }
+    }
     /*
      * N.B. ACPI 1.0 operating systems may not handle FADT with revision 2
      * or above properly, notably Windows 2000, which tries to copy FADT
diff --git a/tools/firmware/hvmloader/acpi/dsdt.asl b/tools/firmware/hvmloader/acpi/dsdt.asl
index 247a8ad..1e7695b 100644
--- a/tools/firmware/hvmloader/acpi/dsdt.asl
+++ b/tools/firmware/hvmloader/acpi/dsdt.asl
@@ -16,6 +16,7 @@
  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  * Place - Suite 330, Boston, MA 02111-1307 USA.
  */
+ACPI_EXTRACT_ALL_CODE AmlCode
 
 DefinitionBlock ("DSDT.aml", "DSDT", 2, "Xen", "HVM", 0)
 {
diff --git a/tools/firmware/hvmloader/acpi/mk_dsdt.c b/tools/firmware/hvmloader/acpi/mk_dsdt.c
index 996f30b..4180801 100644
--- a/tools/firmware/hvmloader/acpi/mk_dsdt.c
+++ b/tools/firmware/hvmloader/acpi/mk_dsdt.c
@@ -368,7 +368,9 @@ int main(int argc, char **argv)
         /* hotplug_slot */
         for (slot = 1; slot <= 31; slot++) {
             push_block("Device", "S%i", slot); {
+                printf("ACPI_EXTRACT_NAME_DWORD_CONST aml_adr_dword\n");
                 stmt("Name", "_ADR, %#06x0000", slot);
+                printf("ACPI_EXTRACT_METHOD_STRING aml_ej0_name\n");
                 push_block("Method", "_EJ0,1"); {
                     stmt("Store", "ShiftLeft(1, %#06x), B0EJ", slot);
                     stmt("Return", "0x0");
diff --git a/tools/firmware/hvmloader/ovmf.c b/tools/firmware/hvmloader/ovmf.c
index ee4cbbf..27ff0b5 100644
--- a/tools/firmware/hvmloader/ovmf.c
+++ b/tools/firmware/hvmloader/ovmf.c
@@ -79,7 +79,11 @@ static void ovmf_acpi_build_tables(void)
         .dsdt_anycpu = dsdt_anycpu,
         .dsdt_anycpu_len = dsdt_anycpu_len,
         .dsdt_15cpu = NULL, 
-        .dsdt_15cpu_len = 0
+        .dsdt_15cpu_len = 0,
+        .aml_ej0_name = NULL,
+        .aml_adr_dword = NULL,
+        .aml_ej0_name_len = 0,
+        .aml_adr_dword_len = 0,
     };
 
     acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
diff --git a/tools/firmware/hvmloader/rombios.c b/tools/firmware/hvmloader/rombios.c
index 810bd24..803c9fa 100644
--- a/tools/firmware/hvmloader/rombios.c
+++ b/tools/firmware/hvmloader/rombios.c
@@ -179,6 +179,10 @@ static void rombios_acpi_build_tables(void)
         .dsdt_anycpu_len = dsdt_anycpu_len,
         .dsdt_15cpu = dsdt_15cpu,
         .dsdt_15cpu_len = dsdt_15cpu_len,
+        .aml_ej0_name = NULL,
+        .aml_adr_dword = NULL,
+        .aml_ej0_name_len = 0,
+        .aml_adr_dword_len = 0,
     };
 
     acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
diff --git a/tools/firmware/hvmloader/seabios.c b/tools/firmware/hvmloader/seabios.c
index dd7dfbe..ca01d27 100644
--- a/tools/firmware/hvmloader/seabios.c
+++ b/tools/firmware/hvmloader/seabios.c
@@ -33,6 +33,10 @@
 
 extern unsigned char dsdt_anycpu_qemu_xen[];
 extern int dsdt_anycpu_qemu_xen_len;
+extern unsigned short dsdt_anycpu_qemu_xen_aml_ej0_name[];
+extern unsigned short dsdt_anycpu_qemu_xen_aml_adr_dword[];
+extern int dsdt_anycpu_qemu_xen_aml_ej0_name_len;
+extern int dsdt_anycpu_qemu_xen_aml_adr_dword_len;
 
 struct seabios_info {
     char signature[14]; /* XenHVMSeaBIOS\0 */
@@ -99,6 +103,10 @@ static void seabios_acpi_build_tables(void)
         .dsdt_anycpu_len = dsdt_anycpu_qemu_xen_len,
         .dsdt_15cpu = NULL,
         .dsdt_15cpu_len = 0,
+        .aml_ej0_name = dsdt_anycpu_qemu_xen_aml_ej0_name,
+        .aml_adr_dword = dsdt_anycpu_qemu_xen_aml_adr_dword,
+        .aml_ej0_name_len = dsdt_anycpu_qemu_xen_aml_ej0_name_len,
+        .aml_adr_dword_len = dsdt_anycpu_qemu_xen_aml_adr_dword_len,
     };
 
     acpi_build_tables(&config, rsdp);
diff --git a/tools/firmware/hvmloader/tools/acpi_extract.py b/tools/firmware/hvmloader/tools/acpi_extract.py
new file mode 100644
index 0000000..4fa51f7
--- /dev/null
+++ b/tools/firmware/hvmloader/tools/acpi_extract.py
@@ -0,0 +1,308 @@
+#!/usr/bin/python
+# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+# Process mixed ASL/AML listing (.lst file) produced by iasl -l
+# Locate and execute ACPI_EXTRACT directives, output offset info
+# 
+# Documentation of ACPI_EXTRACT_* directive tags:
+# 
+# These directive tags output offset information from AML for BIOS runtime
+# table generation.
+# Each directive is of the form:
+# ACPI_EXTRACT_<TYPE> <array_name> <Operator> (...)
+# and causes the extractor to create an array
+# named <array_name> with offset, in the generated AML,
+# of an object of a given type in the following <Operator>.
+# 
+# A directive must fit on a single code line.
+# 
+# Object type in AML is verified, a mismatch causes a build failure.
+# 
+# Directives and operators currently supported are:
+# ACPI_EXTRACT_NAME_DWORD_CONST - extract a Dword Const object from Name()
+# ACPI_EXTRACT_NAME_WORD_CONST - extract a Word Const object from Name()
+# ACPI_EXTRACT_NAME_BYTE_CONST - extract a Byte Const object from Name()
+# ACPI_EXTRACT_METHOD_STRING - extract a NameString from Method()
+# ACPI_EXTRACT_NAME_STRING - extract a NameString from Name()
+# ACPI_EXTRACT_PROCESSOR_START - start of Processor() block
+# ACPI_EXTRACT_PROCESSOR_STRING - extract a NameString from Processor()
+# ACPI_EXTRACT_PROCESSOR_END - offset at last byte of Processor() + 1
+# ACPI_EXTRACT_PKG_START - start of Package block
+#
+# ACPI_EXTRACT_ALL_CODE - create an array storing the generated AML bytecode
+# 
+# ACPI_EXTRACT is not allowed anywhere else in code, except in comments.
+
+import re;
+import sys;
+import fileinput;
+
+aml = []
+asl = []
+output = {}
+debug = ""
+
+class asl_line:
+    line = None
+    lineno = None
+    aml_offset = None
+
+def die(diag):
+    sys.stderr.write("Error: %s; %s\n" % (diag, debug))
+    sys.exit(1)
+    
+#Store an ASL command, matching AML offset, and input line (for debugging)
+def add_asl(lineno, line):
+    l = asl_line()
+    l.line = line
+    l.lineno = lineno
+    l.aml_offset = len(aml)
+    asl.append(l)
+
+#Store an AML byte sequence
+#Verify that offset output by iasl matches # of bytes so far
+def add_aml(offset, line):
+    o = int(offset, 16);
+    # Sanity check: offset must match size of code so far
+    if (o != len(aml)):
+        die("Offset 0x%x != 0x%x" % (o, len(aml)))
+    # Strip any trailing dots and ASCII dump after "
+    line = re.sub(r'\s*\.*\s*".*$',"", line)
+    # Strip traling whitespace
+    line = re.sub(r'\s+$',"", line)
+    # Strip leading whitespace
+    line = re.sub(r'^\s+',"", line)
+    # Split on whitespace
+    code = re.split(r'\s+', line)
+    for c in code:
+        # Require a legal hex number, two digits
+        if (not(re.search(r'^[0-9A-Fa-f][0-9A-Fa-f]$', c))):
+            die("Unexpected octet %s" % c);
+        aml.append(int(c, 16));
+
+# Process aml bytecode array, decoding AML
+def aml_pkglen_bytes(offset):
+    # PkgLength can be multibyte. Bits 8-7 give the # of extra bytes.
+    pkglenbytes = aml[offset] >> 6;
+    return pkglenbytes + 1
+
+def aml_pkglen(offset):
+    pkgstart = offset
+    pkglenbytes = aml_pkglen_bytes(offset)
+    pkglen = aml[offset] & 0x3F
+    # If multibyte, first nibble only uses bits 0-3
+    if ((pkglenbytes > 0) and (pkglen & 0x30)):
+        die("PkgLen bytes 0x%x but first nibble 0x%x expected 0x0X" %
+            (pkglen, pkglen))
+    offset += 1
+    pkglenbytes -= 1
+    for i in range(pkglenbytes):
+        pkglen |= aml[offset + i] << (i * 8 + 4)
+    if (len(aml) < pkgstart + pkglen):
+        die("PckgLen 0x%x at offset 0x%x exceeds AML size 0x%x" %
+            (pkglen, offset, len(aml)))
+    return pkglen
+
+# Given method offset, find its NameString offset
+def aml_method_string(offset):
+    #0x14 MethodOp PkgLength NameString MethodFlags TermList
+    if (aml[offset] != 0x14):
+        die( "Method offset 0x%x: expected 0x14 actual 0x%x" %
+             (offset, aml[offset]));
+    offset += 1;
+    pkglenbytes = aml_pkglen_bytes(offset)
+    offset += pkglenbytes;
+    return offset;
+
+# Given name offset, find its NameString offset
+def aml_name_string(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x08):
+        die( "Name offset 0x%x: expected 0x08 actual 0x%x" %
+             (offset, aml[offset]));
+    offset += 1
+    # Block Name Modifier. Skip it.
+    if (aml[offset] == 0x5c or aml[offset] == 0x5e):
+        offset += 1
+    return offset;
+
+# Given data offset, find dword const offset
+def aml_data_dword_const(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x0C):
+        die( "Name offset 0x%x: expected 0x0C actual 0x%x" %
+             (offset, aml[offset]));
+    return offset + 1;
+
+# Given data offset, find word const offset
+def aml_data_word_const(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x0B):
+        die( "Name offset 0x%x: expected 0x0B actual 0x%x" %
+             (offset, aml[offset]));
+    return offset + 1;
+
+# Given data offset, find byte const offset
+def aml_data_byte_const(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x0A):
+        die( "Name offset 0x%x: expected 0x0A actual 0x%x" %
+             (offset, aml[offset]));
+    return offset + 1;
+
+# Given name offset, find dword const offset
+def aml_name_dword_const(offset):
+    return aml_data_dword_const(aml_name_string(offset) + 4)
+
+# Given name offset, find word const offset
+def aml_name_word_const(offset):
+    return aml_data_word_const(aml_name_string(offset) + 4)
+
+# Given name offset, find byte const offset
+def aml_name_byte_const(offset):
+    return aml_data_byte_const(aml_name_string(offset) + 4)
+
+def aml_processor_start(offset):
+    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
+    if ((aml[offset] != 0x5B) or (aml[offset + 1] != 0x83)):
+        die( "Name offset 0x%x: expected 0x5B 0x83 actual 0x%x 0x%x" %
+             (offset, aml[offset], aml[offset + 1]));
+    return offset
+
+def aml_processor_string(offset):
+    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
+    start = aml_processor_start(offset)
+    offset += 2
+    pkglenbytes = aml_pkglen_bytes(offset)
+    offset += pkglenbytes
+    return offset
+
+def aml_processor_end(offset):
+    start = aml_processor_start(offset)
+    offset += 2
+    pkglenbytes = aml_pkglen_bytes(offset)
+    pkglen = aml_pkglen(offset)
+    return offset + pkglen
+
+def aml_package_start(offset):
+    offset = aml_name_string(offset) + 4
+    # 0x12 PkgLength NumElements PackageElementList
+    if (aml[offset] != 0x12):
+        die( "Name offset 0x%x: expected 0x12 actual 0x%x" %
+             (offset, aml[offset]));
+    offset += 1
+    return offset + aml_pkglen_bytes(offset) + 1
+
+lineno = 0
+for line in fileinput.input():
+    # Strip trailing newline
+    line = line.rstrip();
+    # line number and debug string to output in case of errors
+    lineno = lineno + 1
+    debug = "input line %d: %s" % (lineno, line)
+    #ASL listing: space, then line#, then ...., then code
+    pasl = re.compile('^\s+([0-9]+)\.\.\.\.\s*')
+    m = pasl.search(line)
+    if (m):
+        add_asl(lineno, pasl.sub("", line));
+    # AML listing: offset in hex, then ...., then code
+    paml = re.compile('^([0-9A-Fa-f]+)\.\.\.\.\s*')
+    m = paml.search(line)
+    if (m):
+        add_aml(m.group(1), paml.sub("", line))
+
+# Now go over code
+# Track AML offset of a previous non-empty ASL command
+prev_aml_offset = -1
+for i in range(len(asl)):
+    debug = "input line %d: %s" % (asl[i].lineno, asl[i].line)
+
+    l = asl[i].line
+
+    # skip if not an extract directive
+    a = len(re.findall(r'ACPI_EXTRACT', l))
+    if (not a):
+        # If not empty, store AML offset. Will be used for sanity checks
+        # IASL seems to put {}. at random places in the listing.
+        # Ignore any non-words for the purpose of this test.
+        m = re.search(r'\w+', l)
+        if (m):
+                prev_aml_offset = asl[i].aml_offset
+        continue
+
+    if (a > 1):
+        die("Expected at most one ACPI_EXTRACT per line, actual %d" % a)
+
+    mext = re.search(r'''
+                      ^\s* # leading whitespace
+                      /\*\s* # start C comment
+                      (ACPI_EXTRACT_\w+) # directive: group(1)
+                      \s+ # whitspace separates directive from array name
+                      (\w+) # array name: group(2)
+                      \s*\*/ # end of C comment
+                      \s*$ # trailing whitespace
+                      ''', l, re.VERBOSE)
+    if (not mext):
+        die("Stray ACPI_EXTRACT in input")
+
+    # previous command must have produced some AML,
+    # otherwise we are in a middle of a block
+    if (prev_aml_offset == asl[i].aml_offset):
+        die("ACPI_EXTRACT directive in the middle of a block")
+
+    directive = mext.group(1)
+    array = mext.group(2)
+    offset = asl[i].aml_offset
+
+    if (directive == "ACPI_EXTRACT_ALL_CODE"):
+        if array in output:
+            die("%s directive used more than once" % directive)
+        output[array] = aml
+        continue
+    if (directive == "ACPI_EXTRACT_NAME_DWORD_CONST"):
+        offset = aml_name_dword_const(offset)
+    elif (directive == "ACPI_EXTRACT_NAME_WORD_CONST"):
+        offset = aml_name_word_const(offset)
+    elif (directive == "ACPI_EXTRACT_NAME_BYTE_CONST"):
+        offset = aml_name_byte_const(offset)
+    elif (directive == "ACPI_EXTRACT_NAME_STRING"):
+        offset = aml_name_string(offset)
+    elif (directive == "ACPI_EXTRACT_METHOD_STRING"):
+        offset = aml_method_string(offset)
+    elif (directive == "ACPI_EXTRACT_PROCESSOR_START"):
+        offset = aml_processor_start(offset)
+    elif (directive == "ACPI_EXTRACT_PROCESSOR_STRING"):
+        offset = aml_processor_string(offset)
+    elif (directive == "ACPI_EXTRACT_PROCESSOR_END"):
+        offset = aml_processor_end(offset)
+    elif (directive == "ACPI_EXTRACT_PKG_START"):
+        offset = aml_package_start(offset)
+    else:
+        die("Unsupported directive %s" % directive)
+
+    if array not in output:
+        output[array] = []
+    output[array].append(offset)
+
+debug = "at end of file"
+
+def get_value_type(maxvalue):
+    #Use type large enough to fit the table
+    if (maxvalue >= 0x10000):
+            return "int"
+    elif (maxvalue >= 0x100):
+            return "short"
+    else:
+            return "char"
+
+# Pretty print output
+for array in output.keys():
+    otype = get_value_type(max(output[array]))
+    odata = []
+    for value in output[array]:
+        odata.append("0x%x" % value)
+    sys.stdout.write("unsigned %s %s[] = {\n" % (otype, array))
+    sys.stdout.write(",\n".join(odata))
+    sys.stdout.write('\n};\n');
diff --git a/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py b/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py
new file mode 100644
index 0000000..4ae364e
--- /dev/null
+++ b/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py
@@ -0,0 +1,41 @@
+#!/usr/bin/python
+# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+# Read a preprocessed ASL listing and put each ACPI_EXTRACT
+# directive in a comment, to make iasl skip it.
+# We also put each directive on a new line, the machinery
+# in tools/acpi_extract.py requires this.
+
+import re;
+import sys;
+import fileinput;
+
+def die(diag):
+    sys.stderr.write("Error: %s\n" % (diag))
+    sys.exit(1)
+
+# Note: () around pattern make split return matched string as part of list
+psplit = re.compile(r''' (
+                          \b # At word boundary
+                          ACPI_EXTRACT_\w+ # directive
+                          \s+ # some whitespace
+                          \w+ # array name
+                         )''', re.VERBOSE);
+
+lineno = 0
+for line in fileinput.input():
+    # line number and debug string to output in case of errors
+    lineno = lineno + 1
+    debug = "input line %d: %s" % (lineno, line.rstrip())
+
+    s = psplit.split(line);
+    # The way split works, each odd item is the matching ACPI_EXTRACT directive.
+    # Put each in a comment, and on a line by itself.
+    for i in range(len(s)):
+        if (i % 2):
+            sys.stdout.write("\n/* %s */\n" % s[i])
+        else:
+            sys.stdout.write(s[i])
+
-- 
1.8.3.4


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
  2013-10-22  8:06               ` [Qemu-devel] [Xen-devel] " Jan Beulich
@ 2013-10-24 12:17                 ` Gonglei (Arei)
  2013-10-24 12:17                 ` [Qemu-devel] [Xen-devel] " Gonglei (Arei)
                                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 38+ messages in thread
From: Gonglei (Arei) @ 2013-10-24 12:17 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Yanqiangjun, Ian Campbell, Hanweidong (Randy),
	Markus Armbruster, Stefano Stabellini, Luonengjun, qemu-devel,
	xen-devel, Fabio Fantoni, anthony.perard, Gaowei (UVP),
	Huangweidong (Hardware)

[-- Attachment #1: Type: text/plain, Size: 25259 bytes --]


> -----Original Message-----
> From: Jan Beulich [mailto:JBeulich@suse.com]
> Sent: Tuesday, October 22, 2013 4:06 PM
> To: Gonglei (Arei)
> Cc: anthony.perard@citrix.com; Ian Campbell; Stefano Stabellini; Gaowei (UVP);
> Hanweidong (Randy); Huangweidong (Hardware); Luonengjun; Yanqiangjun;
> xen-devel@lists.xen.org; Fabio Fantoni; qemu-devel@nongnu.org; Markus
> Armbruster
> Subject: RE: [Qemu-devel] [Xen-devel] Hvmloader: Modify ACPI to only supply
> _EJ0 methods for PCIslots that support hotplug by runtime patching
> 
> >>> On 22.10.13 at 06:08, "Gonglei (Arei)" <arei.gonglei@huawei.com> wrote:
> > Hi, guys. The new patch has been modified based on the principles you
> > suggested, thank you so much.
> > Last time I test the patch based on the codes of 4.3.0.
> > This time, I found that the system based on the codes of trunk causes the VM
> > reboot again and again, which I have not found out the reason.
> > So i can not test the patch based on the codes of trunk (details in
> > EJ0_ACPI_PCI_Hotplug.patch)..
> 
> I'm afraid we will need you to figure out that problem first, and
> then do the verification on -unstable. Even if the code shouldn't
> be that different from 4.3, we still don't want to apply completely
> untested stuff.

Hi, Jan. We found that the reason that we used a wrong seabios PATH, and the hvmloader can't load the bios.bin.
So the VM restart again and again after we start it. That's our fault.

Now I test the patch based on the codes of trunk, which works well.
The patch has been modified after your suggestion.
The patch works well with upstream qemu and doesn't affect the system with traditional qemu.

> 
> 
> > --- a/tools/firmware/hvmloader/ovmf.c
> > +++ b/tools/firmware/hvmloader/ovmf.c
> > @@ -79,7 +79,11 @@ static void ovmf_acpi_build_tables(void)
> >          .dsdt_anycpu = dsdt_anycpu,
> >          .dsdt_anycpu_len = dsdt_anycpu_len,
> >          .dsdt_15cpu = NULL,
> > -        .dsdt_15cpu_len = 0
> > +        .dsdt_15cpu_len = 0,
> > +        .aml_ej0_name = NULL,
> > +        .aml_adr_dword = NULL,
> > +        .aml_ej0_name_len = 0,
> > +        .aml_adr_dword_len = 0,
> 
> I don't see why you're adding these.
> 
Insurance purposes is that just initialize the struct.

Signed-off-by: Gaowei <gao.gaowei@huawei.com>
Signed-off-by: gonglei <arei.gonglei@huawei.com>
---
 tools/firmware/hvmloader/acpi/Makefile             |  37 ++-
 tools/firmware/hvmloader/acpi/acpi2_0.h            |   4 +
 tools/firmware/hvmloader/acpi/build.c              |  21 +-
 tools/firmware/hvmloader/acpi/dsdt.asl             |   1 +
 tools/firmware/hvmloader/acpi/mk_dsdt.c            |   2 +
 tools/firmware/hvmloader/ovmf.c                    |   6 +-
 tools/firmware/hvmloader/rombios.c                 |   4 +
 tools/firmware/hvmloader/seabios.c                 |   8 +
 tools/firmware/hvmloader/tools/acpi_extract.py     | 308 +++++++++++++++++++++
 .../hvmloader/tools/acpi_extract_preprocess.py     |  41 +++
 10 files changed, 419 insertions(+), 13 deletions(-)
 create mode 100644 tools/firmware/hvmloader/tools/acpi_extract.py
 create mode 100644 tools/firmware/hvmloader/tools/acpi_extract_preprocess.py

diff --git a/tools/firmware/hvmloader/acpi/Makefile b/tools/firmware/hvmloader/acpi/Makefile
index 2c50851..b96e058 100644
--- a/tools/firmware/hvmloader/acpi/Makefile
+++ b/tools/firmware/hvmloader/acpi/Makefile
@@ -24,30 +24,45 @@ OBJS  = $(patsubst %.c,%.o,$(C_SRC))
 CFLAGS += $(CFLAGS_xeninclude)
 
 vpath iasl $(PATH)
+
+.DELETE_ON_ERROR: $(filter dsdt_%.c,$(C_SRC))
+
 all: acpi.a
 
 ssdt_s3.h ssdt_s4.h ssdt_pm.h ssdt_tpm.h: %.h: %.asl iasl
 	iasl -vs -p $* -tc $<
-	sed -e 's/AmlCode/$*/g' $*.hex >$@
+	sed -e 's/AmlCode/$*/g' $*.hex > $@.tmp
+	$(call move-if-changed,$@.tmp $@)
 	rm -f $*.hex $*.aml
 
 mk_dsdt: mk_dsdt.c
 	$(HOSTCC) $(HOSTCFLAGS) $(CFLAGS_xeninclude) -o $@ mk_dsdt.c
 
 dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
-	awk 'NR > 1 {print s} {s=$$0}' $< > $@
-	./mk_dsdt --dm-version qemu-xen >> $@
+	awk 'NR > 1 {print s} {s=$$0}' $< > $@.tmp
+	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@.tmp
+	./mk_dsdt --dm-version qemu-xen >> $@.tmp
+	sed -i 's/aml_ej0_name/dsdt_anycpu_qemu_xen_aml_ej0_name/g' $@.tmp
+	sed -i 's/aml_adr_dword/dsdt_anycpu_qemu_xen_aml_adr_dword/g' $@.tmp
+	$(call move-if-changed,$@.tmp $@)
 
 # NB. awk invocation is a portable alternative to 'head -n -1'
 dsdt_%cpu.asl: dsdt.asl mk_dsdt
-	awk 'NR > 1 {print s} {s=$$0}' $< > $@
-	./mk_dsdt --maxcpu $*  >> $@
+	awk 'NR > 1 {print s} {s=$$0}' $< > $@.tmp
+	sed -i 's/AmlCode/dsdt_$*cpu/g' $@.tmp
+	./mk_dsdt --maxcpu $*  >> $@.tmp
+	$(call move-if-changed,$@.tmp $@)
 
-$(filter dsdt_%.c,$(C_SRC)): %.c: iasl %.asl
-	iasl -vs -p $* -tc $*.asl
-	sed -e 's/AmlCode/$*/g' $*.hex >$@
-	echo "int $*_len=sizeof($*);" >>$@
-	rm -f $*.aml $*.hex
+$(filter dsdt_%.c,$(C_SRC)): %.c: %.asl iasl
+	cpp -P $< > $<.i.orig
+	$(PYTHON) ../tools/acpi_extract_preprocess.py $<.i.orig > $<.i
+	iasl -vs -l -tc -p $* $<.i
+	$(PYTHON) ../tools/acpi_extract.py $*.lst > $@.tmp
+	echo "int $*_len=sizeof($*);" >> $@.tmp
+	if grep -q "$*_aml_ej0_name" $@.tmp; then echo "int $*_aml_ej0_name_len=sizeof($*_aml_ej0_name);" >> $@.tmp; fi
+	if grep -q "$*_aml_adr_dword" $@.tmp; then echo "int $*_aml_adr_dword_len=sizeof($*_aml_adr_dword);" >> $@.tmp; fi
+	$(call move-if-changed,$@.tmp $@)
+	rm -f $*.aml $*.hex $*.asl.i.orig $*.asl.i $*.lst
 
 iasl:
 	@echo
@@ -64,7 +79,7 @@ acpi.a: $(OBJS)
 
 clean:
 	rm -rf *.a *.o $(IASL_VER) $(IASL_VER).tar.gz $(DEPS)
-	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl
+	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl *.asl.i *.asl.i.orig *.lst *.tmp
 
 install: all
 
diff --git a/tools/firmware/hvmloader/acpi/acpi2_0.h b/tools/firmware/hvmloader/acpi/acpi2_0.h
index 7b22d80..4ba3957 100644
--- a/tools/firmware/hvmloader/acpi/acpi2_0.h
+++ b/tools/firmware/hvmloader/acpi/acpi2_0.h
@@ -396,6 +396,10 @@ struct acpi_config {
     int dsdt_anycpu_len;
     unsigned char *dsdt_15cpu;
     int dsdt_15cpu_len;
+    unsigned short *aml_ej0_name;
+    unsigned short *aml_adr_dword;
+    int aml_ej0_name_len;
+    int aml_adr_dword_len;
 };
 
 void acpi_build_tables(struct acpi_config *config, unsigned int physical);
diff --git a/tools/firmware/hvmloader/acpi/build.c b/tools/firmware/hvmloader/acpi/build.c
index f1dd3f0..7eb21d3 100644
--- a/tools/firmware/hvmloader/acpi/build.c
+++ b/tools/firmware/hvmloader/acpi/build.c
@@ -29,6 +29,7 @@
 
 #define align16(sz)        (((sz) + 15) & ~15)
 #define fixed_strcpy(d, s) strncpy((d), (s), sizeof(d))
+#define PCI_RMV_BASE 0xae0c
 
 extern struct acpi_20_rsdp Rsdp;
 extern struct acpi_20_rsdt Rsdt;
@@ -404,6 +405,7 @@ void acpi_build_tables(struct acpi_config *config, unsigned int physical)
     unsigned char       *dsdt;
     unsigned long        secondary_tables[ACPI_MAX_SECONDARY_TABLES];
     int                  nr_secondaries, i;
+    unsigned int rmvc_pcrm = 0;
 
     /* Allocate and initialise the acpi info area. */
     mem_hole_populate_ram(ACPI_INFO_PHYSICAL_ADDRESS >> PAGE_SHIFT, 1);
@@ -440,7 +442,24 @@ void acpi_build_tables(struct acpi_config *config, unsigned int physical)
         memcpy(dsdt, config->dsdt_anycpu, config->dsdt_anycpu_len);
         nr_processor_objects = HVM_MAX_VCPUS;
     }
-
+    if(config->aml_adr_dword_len && config->aml_ej0_name_len &&
+        (config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]) == config->aml_ej0_name_len/sizeof(config->aml_ej0_name[0])))
+    {
+        rmvc_pcrm = inl(PCI_RMV_BASE); 
+        for(i = 0;  i < config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]); i ++)
+        {
+            /* Slot is in byte 2 in _ADR */
+            unsigned char slot = dsdt[config->aml_adr_dword[i] + 2] & 0x1F;
+            /* Sanity check */
+            if (memcmp(dsdt + config->aml_ej0_name[i], "_EJ0", 4)) {
+                printf("Method '_EJ0' can not be found for pci slot %d\n", slot);
+                return;
+            }
+            if (!(rmvc_pcrm & (0x1 << slot))) {
+                memcpy(dsdt + config->aml_ej0_name[i], "EJ0_", 4);
+            }
+        }
+    }
     /*
      * N.B. ACPI 1.0 operating systems may not handle FADT with revision 2
      * or above properly, notably Windows 2000, which tries to copy FADT
diff --git a/tools/firmware/hvmloader/acpi/dsdt.asl b/tools/firmware/hvmloader/acpi/dsdt.asl
index 247a8ad..1e7695b 100644
--- a/tools/firmware/hvmloader/acpi/dsdt.asl
+++ b/tools/firmware/hvmloader/acpi/dsdt.asl
@@ -16,6 +16,7 @@
  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  * Place - Suite 330, Boston, MA 02111-1307 USA.
  */
+ACPI_EXTRACT_ALL_CODE AmlCode
 
 DefinitionBlock ("DSDT.aml", "DSDT", 2, "Xen", "HVM", 0)
 {
diff --git a/tools/firmware/hvmloader/acpi/mk_dsdt.c b/tools/firmware/hvmloader/acpi/mk_dsdt.c
index 996f30b..4180801 100644
--- a/tools/firmware/hvmloader/acpi/mk_dsdt.c
+++ b/tools/firmware/hvmloader/acpi/mk_dsdt.c
@@ -368,7 +368,9 @@ int main(int argc, char **argv)
         /* hotplug_slot */
         for (slot = 1; slot <= 31; slot++) {
             push_block("Device", "S%i", slot); {
+                printf("ACPI_EXTRACT_NAME_DWORD_CONST aml_adr_dword\n");
                 stmt("Name", "_ADR, %#06x0000", slot);
+                printf("ACPI_EXTRACT_METHOD_STRING aml_ej0_name\n");
                 push_block("Method", "_EJ0,1"); {
                     stmt("Store", "ShiftLeft(1, %#06x), B0EJ", slot);
                     stmt("Return", "0x0");
diff --git a/tools/firmware/hvmloader/ovmf.c b/tools/firmware/hvmloader/ovmf.c
index ee4cbbf..27ff0b5 100644
--- a/tools/firmware/hvmloader/ovmf.c
+++ b/tools/firmware/hvmloader/ovmf.c
@@ -79,7 +79,11 @@ static void ovmf_acpi_build_tables(void)
         .dsdt_anycpu = dsdt_anycpu,
         .dsdt_anycpu_len = dsdt_anycpu_len,
         .dsdt_15cpu = NULL, 
-        .dsdt_15cpu_len = 0
+        .dsdt_15cpu_len = 0,
+        .aml_ej0_name = NULL,
+        .aml_adr_dword = NULL,
+        .aml_ej0_name_len = 0,
+        .aml_adr_dword_len = 0,
     };
 
     acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
diff --git a/tools/firmware/hvmloader/rombios.c b/tools/firmware/hvmloader/rombios.c
index 810bd24..803c9fa 100644
--- a/tools/firmware/hvmloader/rombios.c
+++ b/tools/firmware/hvmloader/rombios.c
@@ -179,6 +179,10 @@ static void rombios_acpi_build_tables(void)
         .dsdt_anycpu_len = dsdt_anycpu_len,
         .dsdt_15cpu = dsdt_15cpu,
         .dsdt_15cpu_len = dsdt_15cpu_len,
+        .aml_ej0_name = NULL,
+        .aml_adr_dword = NULL,
+        .aml_ej0_name_len = 0,
+        .aml_adr_dword_len = 0,
     };
 
     acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
diff --git a/tools/firmware/hvmloader/seabios.c b/tools/firmware/hvmloader/seabios.c
index dd7dfbe..ca01d27 100644
--- a/tools/firmware/hvmloader/seabios.c
+++ b/tools/firmware/hvmloader/seabios.c
@@ -33,6 +33,10 @@
 
 extern unsigned char dsdt_anycpu_qemu_xen[];
 extern int dsdt_anycpu_qemu_xen_len;
+extern unsigned short dsdt_anycpu_qemu_xen_aml_ej0_name[];
+extern unsigned short dsdt_anycpu_qemu_xen_aml_adr_dword[];
+extern int dsdt_anycpu_qemu_xen_aml_ej0_name_len;
+extern int dsdt_anycpu_qemu_xen_aml_adr_dword_len;
 
 struct seabios_info {
     char signature[14]; /* XenHVMSeaBIOS\0 */
@@ -99,6 +103,10 @@ static void seabios_acpi_build_tables(void)
         .dsdt_anycpu_len = dsdt_anycpu_qemu_xen_len,
         .dsdt_15cpu = NULL,
         .dsdt_15cpu_len = 0,
+        .aml_ej0_name = dsdt_anycpu_qemu_xen_aml_ej0_name,
+        .aml_adr_dword = dsdt_anycpu_qemu_xen_aml_adr_dword,
+        .aml_ej0_name_len = dsdt_anycpu_qemu_xen_aml_ej0_name_len,
+        .aml_adr_dword_len = dsdt_anycpu_qemu_xen_aml_adr_dword_len,
     };
 
     acpi_build_tables(&config, rsdp);
diff --git a/tools/firmware/hvmloader/tools/acpi_extract.py b/tools/firmware/hvmloader/tools/acpi_extract.py
new file mode 100644
index 0000000..4fa51f7
--- /dev/null
+++ b/tools/firmware/hvmloader/tools/acpi_extract.py
@@ -0,0 +1,308 @@
+#!/usr/bin/python
+# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+# Process mixed ASL/AML listing (.lst file) produced by iasl -l
+# Locate and execute ACPI_EXTRACT directives, output offset info
+# 
+# Documentation of ACPI_EXTRACT_* directive tags:
+# 
+# These directive tags output offset information from AML for BIOS runtime
+# table generation.
+# Each directive is of the form:
+# ACPI_EXTRACT_<TYPE> <array_name> <Operator> (...)
+# and causes the extractor to create an array
+# named <array_name> with offset, in the generated AML,
+# of an object of a given type in the following <Operator>.
+# 
+# A directive must fit on a single code line.
+# 
+# Object type in AML is verified, a mismatch causes a build failure.
+# 
+# Directives and operators currently supported are:
+# ACPI_EXTRACT_NAME_DWORD_CONST - extract a Dword Const object from Name()
+# ACPI_EXTRACT_NAME_WORD_CONST - extract a Word Const object from Name()
+# ACPI_EXTRACT_NAME_BYTE_CONST - extract a Byte Const object from Name()
+# ACPI_EXTRACT_METHOD_STRING - extract a NameString from Method()
+# ACPI_EXTRACT_NAME_STRING - extract a NameString from Name()
+# ACPI_EXTRACT_PROCESSOR_START - start of Processor() block
+# ACPI_EXTRACT_PROCESSOR_STRING - extract a NameString from Processor()
+# ACPI_EXTRACT_PROCESSOR_END - offset at last byte of Processor() + 1
+# ACPI_EXTRACT_PKG_START - start of Package block
+#
+# ACPI_EXTRACT_ALL_CODE - create an array storing the generated AML bytecode
+# 
+# ACPI_EXTRACT is not allowed anywhere else in code, except in comments.
+
+import re;
+import sys;
+import fileinput;
+
+aml = []
+asl = []
+output = {}
+debug = ""
+
+class asl_line:
+    line = None
+    lineno = None
+    aml_offset = None
+
+def die(diag):
+    sys.stderr.write("Error: %s; %s\n" % (diag, debug))
+    sys.exit(1)
+    
+#Store an ASL command, matching AML offset, and input line (for debugging)
+def add_asl(lineno, line):
+    l = asl_line()
+    l.line = line
+    l.lineno = lineno
+    l.aml_offset = len(aml)
+    asl.append(l)
+
+#Store an AML byte sequence
+#Verify that offset output by iasl matches # of bytes so far
+def add_aml(offset, line):
+    o = int(offset, 16);
+    # Sanity check: offset must match size of code so far
+    if (o != len(aml)):
+        die("Offset 0x%x != 0x%x" % (o, len(aml)))
+    # Strip any trailing dots and ASCII dump after "
+    line = re.sub(r'\s*\.*\s*".*$',"", line)
+    # Strip traling whitespace
+    line = re.sub(r'\s+$',"", line)
+    # Strip leading whitespace
+    line = re.sub(r'^\s+',"", line)
+    # Split on whitespace
+    code = re.split(r'\s+', line)
+    for c in code:
+        # Require a legal hex number, two digits
+        if (not(re.search(r'^[0-9A-Fa-f][0-9A-Fa-f]$', c))):
+            die("Unexpected octet %s" % c);
+        aml.append(int(c, 16));
+
+# Process aml bytecode array, decoding AML
+def aml_pkglen_bytes(offset):
+    # PkgLength can be multibyte. Bits 8-7 give the # of extra bytes.
+    pkglenbytes = aml[offset] >> 6;
+    return pkglenbytes + 1
+
+def aml_pkglen(offset):
+    pkgstart = offset
+    pkglenbytes = aml_pkglen_bytes(offset)
+    pkglen = aml[offset] & 0x3F
+    # If multibyte, first nibble only uses bits 0-3
+    if ((pkglenbytes > 0) and (pkglen & 0x30)):
+        die("PkgLen bytes 0x%x but first nibble 0x%x expected 0x0X" %
+            (pkglen, pkglen))
+    offset += 1
+    pkglenbytes -= 1
+    for i in range(pkglenbytes):
+        pkglen |= aml[offset + i] << (i * 8 + 4)
+    if (len(aml) < pkgstart + pkglen):
+        die("PckgLen 0x%x at offset 0x%x exceeds AML size 0x%x" %
+            (pkglen, offset, len(aml)))
+    return pkglen
+
+# Given method offset, find its NameString offset
+def aml_method_string(offset):
+    #0x14 MethodOp PkgLength NameString MethodFlags TermList
+    if (aml[offset] != 0x14):
+        die( "Method offset 0x%x: expected 0x14 actual 0x%x" %
+             (offset, aml[offset]));
+    offset += 1;
+    pkglenbytes = aml_pkglen_bytes(offset)
+    offset += pkglenbytes;
+    return offset;
+
+# Given name offset, find its NameString offset
+def aml_name_string(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x08):
+        die( "Name offset 0x%x: expected 0x08 actual 0x%x" %
+             (offset, aml[offset]));
+    offset += 1
+    # Block Name Modifier. Skip it.
+    if (aml[offset] == 0x5c or aml[offset] == 0x5e):
+        offset += 1
+    return offset;
+
+# Given data offset, find dword const offset
+def aml_data_dword_const(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x0C):
+        die( "Name offset 0x%x: expected 0x0C actual 0x%x" %
+             (offset, aml[offset]));
+    return offset + 1;
+
+# Given data offset, find word const offset
+def aml_data_word_const(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x0B):
+        die( "Name offset 0x%x: expected 0x0B actual 0x%x" %
+             (offset, aml[offset]));
+    return offset + 1;
+
+# Given data offset, find byte const offset
+def aml_data_byte_const(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x0A):
+        die( "Name offset 0x%x: expected 0x0A actual 0x%x" %
+             (offset, aml[offset]));
+    return offset + 1;
+
+# Given name offset, find dword const offset
+def aml_name_dword_const(offset):
+    return aml_data_dword_const(aml_name_string(offset) + 4)
+
+# Given name offset, find word const offset
+def aml_name_word_const(offset):
+    return aml_data_word_const(aml_name_string(offset) + 4)
+
+# Given name offset, find byte const offset
+def aml_name_byte_const(offset):
+    return aml_data_byte_const(aml_name_string(offset) + 4)
+
+def aml_processor_start(offset):
+    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
+    if ((aml[offset] != 0x5B) or (aml[offset + 1] != 0x83)):
+        die( "Name offset 0x%x: expected 0x5B 0x83 actual 0x%x 0x%x" %
+             (offset, aml[offset], aml[offset + 1]));
+    return offset
+
+def aml_processor_string(offset):
+    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
+    start = aml_processor_start(offset)
+    offset += 2
+    pkglenbytes = aml_pkglen_bytes(offset)
+    offset += pkglenbytes
+    return offset
+
+def aml_processor_end(offset):
+    start = aml_processor_start(offset)
+    offset += 2
+    pkglenbytes = aml_pkglen_bytes(offset)
+    pkglen = aml_pkglen(offset)
+    return offset + pkglen
+
+def aml_package_start(offset):
+    offset = aml_name_string(offset) + 4
+    # 0x12 PkgLength NumElements PackageElementList
+    if (aml[offset] != 0x12):
+        die( "Name offset 0x%x: expected 0x12 actual 0x%x" %
+             (offset, aml[offset]));
+    offset += 1
+    return offset + aml_pkglen_bytes(offset) + 1
+
+lineno = 0
+for line in fileinput.input():
+    # Strip trailing newline
+    line = line.rstrip();
+    # line number and debug string to output in case of errors
+    lineno = lineno + 1
+    debug = "input line %d: %s" % (lineno, line)
+    #ASL listing: space, then line#, then ...., then code
+    pasl = re.compile('^\s+([0-9]+)\.\.\.\.\s*')
+    m = pasl.search(line)
+    if (m):
+        add_asl(lineno, pasl.sub("", line));
+    # AML listing: offset in hex, then ...., then code
+    paml = re.compile('^([0-9A-Fa-f]+)\.\.\.\.\s*')
+    m = paml.search(line)
+    if (m):
+        add_aml(m.group(1), paml.sub("", line))
+
+# Now go over code
+# Track AML offset of a previous non-empty ASL command
+prev_aml_offset = -1
+for i in range(len(asl)):
+    debug = "input line %d: %s" % (asl[i].lineno, asl[i].line)
+
+    l = asl[i].line
+
+    # skip if not an extract directive
+    a = len(re.findall(r'ACPI_EXTRACT', l))
+    if (not a):
+        # If not empty, store AML offset. Will be used for sanity checks
+        # IASL seems to put {}. at random places in the listing.
+        # Ignore any non-words for the purpose of this test.
+        m = re.search(r'\w+', l)
+        if (m):
+                prev_aml_offset = asl[i].aml_offset
+        continue
+
+    if (a > 1):
+        die("Expected at most one ACPI_EXTRACT per line, actual %d" % a)
+
+    mext = re.search(r'''
+                      ^\s* # leading whitespace
+                      /\*\s* # start C comment
+                      (ACPI_EXTRACT_\w+) # directive: group(1)
+                      \s+ # whitspace separates directive from array name
+                      (\w+) # array name: group(2)
+                      \s*\*/ # end of C comment
+                      \s*$ # trailing whitespace
+                      ''', l, re.VERBOSE)
+    if (not mext):
+        die("Stray ACPI_EXTRACT in input")
+
+    # previous command must have produced some AML,
+    # otherwise we are in a middle of a block
+    if (prev_aml_offset == asl[i].aml_offset):
+        die("ACPI_EXTRACT directive in the middle of a block")
+
+    directive = mext.group(1)
+    array = mext.group(2)
+    offset = asl[i].aml_offset
+
+    if (directive == "ACPI_EXTRACT_ALL_CODE"):
+        if array in output:
+            die("%s directive used more than once" % directive)
+        output[array] = aml
+        continue
+    if (directive == "ACPI_EXTRACT_NAME_DWORD_CONST"):
+        offset = aml_name_dword_const(offset)
+    elif (directive == "ACPI_EXTRACT_NAME_WORD_CONST"):
+        offset = aml_name_word_const(offset)
+    elif (directive == "ACPI_EXTRACT_NAME_BYTE_CONST"):
+        offset = aml_name_byte_const(offset)
+    elif (directive == "ACPI_EXTRACT_NAME_STRING"):
+        offset = aml_name_string(offset)
+    elif (directive == "ACPI_EXTRACT_METHOD_STRING"):
+        offset = aml_method_string(offset)
+    elif (directive == "ACPI_EXTRACT_PROCESSOR_START"):
+        offset = aml_processor_start(offset)
+    elif (directive == "ACPI_EXTRACT_PROCESSOR_STRING"):
+        offset = aml_processor_string(offset)
+    elif (directive == "ACPI_EXTRACT_PROCESSOR_END"):
+        offset = aml_processor_end(offset)
+    elif (directive == "ACPI_EXTRACT_PKG_START"):
+        offset = aml_package_start(offset)
+    else:
+        die("Unsupported directive %s" % directive)
+
+    if array not in output:
+        output[array] = []
+    output[array].append(offset)
+
+debug = "at end of file"
+
+def get_value_type(maxvalue):
+    #Use type large enough to fit the table
+    if (maxvalue >= 0x10000):
+            return "int"
+    elif (maxvalue >= 0x100):
+            return "short"
+    else:
+            return "char"
+
+# Pretty print output
+for array in output.keys():
+    otype = get_value_type(max(output[array]))
+    odata = []
+    for value in output[array]:
+        odata.append("0x%x" % value)
+    sys.stdout.write("unsigned %s %s[] = {\n" % (otype, array))
+    sys.stdout.write(",\n".join(odata))
+    sys.stdout.write('\n};\n');
diff --git a/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py b/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py
new file mode 100644
index 0000000..4ae364e
--- /dev/null
+++ b/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py
@@ -0,0 +1,41 @@
+#!/usr/bin/python
+# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+# Read a preprocessed ASL listing and put each ACPI_EXTRACT
+# directive in a comment, to make iasl skip it.
+# We also put each directive on a new line, the machinery
+# in tools/acpi_extract.py requires this.
+
+import re;
+import sys;
+import fileinput;
+
+def die(diag):
+    sys.stderr.write("Error: %s\n" % (diag))
+    sys.exit(1)
+
+# Note: () around pattern make split return matched string as part of list
+psplit = re.compile(r''' (
+                          \b # At word boundary
+                          ACPI_EXTRACT_\w+ # directive
+                          \s+ # some whitespace
+                          \w+ # array name
+                         )''', re.VERBOSE);
+
+lineno = 0
+for line in fileinput.input():
+    # line number and debug string to output in case of errors
+    lineno = lineno + 1
+    debug = "input line %d: %s" % (lineno, line.rstrip())
+
+    s = psplit.split(line);
+    # The way split works, each odd item is the matching ACPI_EXTRACT directive.
+    # Put each in a comment, and on a line by itself.
+    for i in range(len(s)):
+        if (i % 2):
+            sys.stdout.write("\n/* %s */\n" % s[i])
+        else:
+            sys.stdout.write(s[i])
+
-- 
1.8.3.4

Best regards,
-Gonglei


[-- Attachment #2: 0001-Hvmloader-Modify-ACPI-to-only-supply-_EJ0-methods-fo.patch --]
[-- Type: application/octet-stream, Size: 23408 bytes --]

From 1a23acffa55e5ed4c1df860bdacd4e485d74861f Mon Sep 17 00:00:00 2001
From: Gaowei <gao.gaowei@huawei.com>
Date: Thu, 24 Oct 2013 17:19:16 +0800
Subject: [PATCH] Hvmloader: Modify ACPI to only supply _EJ0 methods for
 PCIslots that support hotplug by runtime patching

In Xen platform, after using upstream qemu, the all of pci devices will show hotplug in the windows guest.
In this situation, the windows guest may occur blue screen when VM' user click the icon of VGA card for trying unplug VGA card.
However, we don't hope VM's user can do such dangerous operation, and showing all pci devices inside the guest OS is unfriendly.
This is done by runtime patching:
  - Rename _EJ0 methods for PCI slots in DSDT to EJ0_:note that this has the same checksum, but is ignored by OSPM.
  - At compile time, look for these methods in ASL source,find the matching AML, and store the offsets of these methods in a table named aml_ej0_data.
  - At run time, go over aml_ej0_data, check which slots not support hotplug and patch the ACPI table, replacing _EJ0 with EJ0_.

Signed-off-by: Gaowei <gao.gaowei@huawei.com>
Signed-off-by: gonglei <arei.gonglei@huawei.com>
---
 tools/firmware/hvmloader/acpi/Makefile             |  37 ++-
 tools/firmware/hvmloader/acpi/acpi2_0.h            |   4 +
 tools/firmware/hvmloader/acpi/build.c              |  21 +-
 tools/firmware/hvmloader/acpi/dsdt.asl             |   1 +
 tools/firmware/hvmloader/acpi/mk_dsdt.c            |   2 +
 tools/firmware/hvmloader/ovmf.c                    |   6 +-
 tools/firmware/hvmloader/rombios.c                 |   4 +
 tools/firmware/hvmloader/seabios.c                 |   8 +
 tools/firmware/hvmloader/tools/acpi_extract.py     | 308 +++++++++++++++++++++
 .../hvmloader/tools/acpi_extract_preprocess.py     |  41 +++
 10 files changed, 419 insertions(+), 13 deletions(-)
 create mode 100644 tools/firmware/hvmloader/tools/acpi_extract.py
 create mode 100644 tools/firmware/hvmloader/tools/acpi_extract_preprocess.py

diff --git a/tools/firmware/hvmloader/acpi/Makefile b/tools/firmware/hvmloader/acpi/Makefile
index 2c50851..b96e058 100644
--- a/tools/firmware/hvmloader/acpi/Makefile
+++ b/tools/firmware/hvmloader/acpi/Makefile
@@ -24,30 +24,45 @@ OBJS  = $(patsubst %.c,%.o,$(C_SRC))
 CFLAGS += $(CFLAGS_xeninclude)
 
 vpath iasl $(PATH)
+
+.DELETE_ON_ERROR: $(filter dsdt_%.c,$(C_SRC))
+
 all: acpi.a
 
 ssdt_s3.h ssdt_s4.h ssdt_pm.h ssdt_tpm.h: %.h: %.asl iasl
 	iasl -vs -p $* -tc $<
-	sed -e 's/AmlCode/$*/g' $*.hex >$@
+	sed -e 's/AmlCode/$*/g' $*.hex > $@.tmp
+	$(call move-if-changed,$@.tmp $@)
 	rm -f $*.hex $*.aml
 
 mk_dsdt: mk_dsdt.c
 	$(HOSTCC) $(HOSTCFLAGS) $(CFLAGS_xeninclude) -o $@ mk_dsdt.c
 
 dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
-	awk 'NR > 1 {print s} {s=$$0}' $< > $@
-	./mk_dsdt --dm-version qemu-xen >> $@
+	awk 'NR > 1 {print s} {s=$$0}' $< > $@.tmp
+	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@.tmp
+	./mk_dsdt --dm-version qemu-xen >> $@.tmp
+	sed -i 's/aml_ej0_name/dsdt_anycpu_qemu_xen_aml_ej0_name/g' $@.tmp
+	sed -i 's/aml_adr_dword/dsdt_anycpu_qemu_xen_aml_adr_dword/g' $@.tmp
+	$(call move-if-changed,$@.tmp $@)
 
 # NB. awk invocation is a portable alternative to 'head -n -1'
 dsdt_%cpu.asl: dsdt.asl mk_dsdt
-	awk 'NR > 1 {print s} {s=$$0}' $< > $@
-	./mk_dsdt --maxcpu $*  >> $@
+	awk 'NR > 1 {print s} {s=$$0}' $< > $@.tmp
+	sed -i 's/AmlCode/dsdt_$*cpu/g' $@.tmp
+	./mk_dsdt --maxcpu $*  >> $@.tmp
+	$(call move-if-changed,$@.tmp $@)
 
-$(filter dsdt_%.c,$(C_SRC)): %.c: iasl %.asl
-	iasl -vs -p $* -tc $*.asl
-	sed -e 's/AmlCode/$*/g' $*.hex >$@
-	echo "int $*_len=sizeof($*);" >>$@
-	rm -f $*.aml $*.hex
+$(filter dsdt_%.c,$(C_SRC)): %.c: %.asl iasl
+	cpp -P $< > $<.i.orig
+	$(PYTHON) ../tools/acpi_extract_preprocess.py $<.i.orig > $<.i
+	iasl -vs -l -tc -p $* $<.i
+	$(PYTHON) ../tools/acpi_extract.py $*.lst > $@.tmp
+	echo "int $*_len=sizeof($*);" >> $@.tmp
+	if grep -q "$*_aml_ej0_name" $@.tmp; then echo "int $*_aml_ej0_name_len=sizeof($*_aml_ej0_name);" >> $@.tmp; fi
+	if grep -q "$*_aml_adr_dword" $@.tmp; then echo "int $*_aml_adr_dword_len=sizeof($*_aml_adr_dword);" >> $@.tmp; fi
+	$(call move-if-changed,$@.tmp $@)
+	rm -f $*.aml $*.hex $*.asl.i.orig $*.asl.i $*.lst
 
 iasl:
 	@echo
@@ -64,7 +79,7 @@ acpi.a: $(OBJS)
 
 clean:
 	rm -rf *.a *.o $(IASL_VER) $(IASL_VER).tar.gz $(DEPS)
-	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl
+	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl *.asl.i *.asl.i.orig *.lst *.tmp
 
 install: all
 
diff --git a/tools/firmware/hvmloader/acpi/acpi2_0.h b/tools/firmware/hvmloader/acpi/acpi2_0.h
index 7b22d80..4ba3957 100644
--- a/tools/firmware/hvmloader/acpi/acpi2_0.h
+++ b/tools/firmware/hvmloader/acpi/acpi2_0.h
@@ -396,6 +396,10 @@ struct acpi_config {
     int dsdt_anycpu_len;
     unsigned char *dsdt_15cpu;
     int dsdt_15cpu_len;
+    unsigned short *aml_ej0_name;
+    unsigned short *aml_adr_dword;
+    int aml_ej0_name_len;
+    int aml_adr_dword_len;
 };
 
 void acpi_build_tables(struct acpi_config *config, unsigned int physical);
diff --git a/tools/firmware/hvmloader/acpi/build.c b/tools/firmware/hvmloader/acpi/build.c
index f1dd3f0..7eb21d3 100644
--- a/tools/firmware/hvmloader/acpi/build.c
+++ b/tools/firmware/hvmloader/acpi/build.c
@@ -29,6 +29,7 @@
 
 #define align16(sz)        (((sz) + 15) & ~15)
 #define fixed_strcpy(d, s) strncpy((d), (s), sizeof(d))
+#define PCI_RMV_BASE 0xae0c
 
 extern struct acpi_20_rsdp Rsdp;
 extern struct acpi_20_rsdt Rsdt;
@@ -404,6 +405,7 @@ void acpi_build_tables(struct acpi_config *config, unsigned int physical)
     unsigned char       *dsdt;
     unsigned long        secondary_tables[ACPI_MAX_SECONDARY_TABLES];
     int                  nr_secondaries, i;
+    unsigned int rmvc_pcrm = 0;
 
     /* Allocate and initialise the acpi info area. */
     mem_hole_populate_ram(ACPI_INFO_PHYSICAL_ADDRESS >> PAGE_SHIFT, 1);
@@ -440,7 +442,24 @@ void acpi_build_tables(struct acpi_config *config, unsigned int physical)
         memcpy(dsdt, config->dsdt_anycpu, config->dsdt_anycpu_len);
         nr_processor_objects = HVM_MAX_VCPUS;
     }
-
+    if(config->aml_adr_dword_len && config->aml_ej0_name_len &&
+        (config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]) == config->aml_ej0_name_len/sizeof(config->aml_ej0_name[0])))
+    {
+        rmvc_pcrm = inl(PCI_RMV_BASE); 
+        for(i = 0;  i < config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]); i ++)
+        {
+            /* Slot is in byte 2 in _ADR */
+            unsigned char slot = dsdt[config->aml_adr_dword[i] + 2] & 0x1F;
+            /* Sanity check */
+            if (memcmp(dsdt + config->aml_ej0_name[i], "_EJ0", 4)) {
+                printf("Method '_EJ0' can not be found for pci slot %d\n", slot);
+                return;
+            }
+            if (!(rmvc_pcrm & (0x1 << slot))) {
+                memcpy(dsdt + config->aml_ej0_name[i], "EJ0_", 4);
+            }
+        }
+    }
     /*
      * N.B. ACPI 1.0 operating systems may not handle FADT with revision 2
      * or above properly, notably Windows 2000, which tries to copy FADT
diff --git a/tools/firmware/hvmloader/acpi/dsdt.asl b/tools/firmware/hvmloader/acpi/dsdt.asl
index 247a8ad..1e7695b 100644
--- a/tools/firmware/hvmloader/acpi/dsdt.asl
+++ b/tools/firmware/hvmloader/acpi/dsdt.asl
@@ -16,6 +16,7 @@
  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  * Place - Suite 330, Boston, MA 02111-1307 USA.
  */
+ACPI_EXTRACT_ALL_CODE AmlCode
 
 DefinitionBlock ("DSDT.aml", "DSDT", 2, "Xen", "HVM", 0)
 {
diff --git a/tools/firmware/hvmloader/acpi/mk_dsdt.c b/tools/firmware/hvmloader/acpi/mk_dsdt.c
index 996f30b..4180801 100644
--- a/tools/firmware/hvmloader/acpi/mk_dsdt.c
+++ b/tools/firmware/hvmloader/acpi/mk_dsdt.c
@@ -368,7 +368,9 @@ int main(int argc, char **argv)
         /* hotplug_slot */
         for (slot = 1; slot <= 31; slot++) {
             push_block("Device", "S%i", slot); {
+                printf("ACPI_EXTRACT_NAME_DWORD_CONST aml_adr_dword\n");
                 stmt("Name", "_ADR, %#06x0000", slot);
+                printf("ACPI_EXTRACT_METHOD_STRING aml_ej0_name\n");
                 push_block("Method", "_EJ0,1"); {
                     stmt("Store", "ShiftLeft(1, %#06x), B0EJ", slot);
                     stmt("Return", "0x0");
diff --git a/tools/firmware/hvmloader/ovmf.c b/tools/firmware/hvmloader/ovmf.c
index ee4cbbf..27ff0b5 100644
--- a/tools/firmware/hvmloader/ovmf.c
+++ b/tools/firmware/hvmloader/ovmf.c
@@ -79,7 +79,11 @@ static void ovmf_acpi_build_tables(void)
         .dsdt_anycpu = dsdt_anycpu,
         .dsdt_anycpu_len = dsdt_anycpu_len,
         .dsdt_15cpu = NULL, 
-        .dsdt_15cpu_len = 0
+        .dsdt_15cpu_len = 0,
+        .aml_ej0_name = NULL,
+        .aml_adr_dword = NULL,
+        .aml_ej0_name_len = 0,
+        .aml_adr_dword_len = 0,
     };
 
     acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
diff --git a/tools/firmware/hvmloader/rombios.c b/tools/firmware/hvmloader/rombios.c
index 810bd24..803c9fa 100644
--- a/tools/firmware/hvmloader/rombios.c
+++ b/tools/firmware/hvmloader/rombios.c
@@ -179,6 +179,10 @@ static void rombios_acpi_build_tables(void)
         .dsdt_anycpu_len = dsdt_anycpu_len,
         .dsdt_15cpu = dsdt_15cpu,
         .dsdt_15cpu_len = dsdt_15cpu_len,
+        .aml_ej0_name = NULL,
+        .aml_adr_dword = NULL,
+        .aml_ej0_name_len = 0,
+        .aml_adr_dword_len = 0,
     };
 
     acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
diff --git a/tools/firmware/hvmloader/seabios.c b/tools/firmware/hvmloader/seabios.c
index dd7dfbe..ca01d27 100644
--- a/tools/firmware/hvmloader/seabios.c
+++ b/tools/firmware/hvmloader/seabios.c
@@ -33,6 +33,10 @@
 
 extern unsigned char dsdt_anycpu_qemu_xen[];
 extern int dsdt_anycpu_qemu_xen_len;
+extern unsigned short dsdt_anycpu_qemu_xen_aml_ej0_name[];
+extern unsigned short dsdt_anycpu_qemu_xen_aml_adr_dword[];
+extern int dsdt_anycpu_qemu_xen_aml_ej0_name_len;
+extern int dsdt_anycpu_qemu_xen_aml_adr_dword_len;
 
 struct seabios_info {
     char signature[14]; /* XenHVMSeaBIOS\0 */
@@ -99,6 +103,10 @@ static void seabios_acpi_build_tables(void)
         .dsdt_anycpu_len = dsdt_anycpu_qemu_xen_len,
         .dsdt_15cpu = NULL,
         .dsdt_15cpu_len = 0,
+        .aml_ej0_name = dsdt_anycpu_qemu_xen_aml_ej0_name,
+        .aml_adr_dword = dsdt_anycpu_qemu_xen_aml_adr_dword,
+        .aml_ej0_name_len = dsdt_anycpu_qemu_xen_aml_ej0_name_len,
+        .aml_adr_dword_len = dsdt_anycpu_qemu_xen_aml_adr_dword_len,
     };
 
     acpi_build_tables(&config, rsdp);
diff --git a/tools/firmware/hvmloader/tools/acpi_extract.py b/tools/firmware/hvmloader/tools/acpi_extract.py
new file mode 100644
index 0000000..4fa51f7
--- /dev/null
+++ b/tools/firmware/hvmloader/tools/acpi_extract.py
@@ -0,0 +1,308 @@
+#!/usr/bin/python
+# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+# Process mixed ASL/AML listing (.lst file) produced by iasl -l
+# Locate and execute ACPI_EXTRACT directives, output offset info
+# 
+# Documentation of ACPI_EXTRACT_* directive tags:
+# 
+# These directive tags output offset information from AML for BIOS runtime
+# table generation.
+# Each directive is of the form:
+# ACPI_EXTRACT_<TYPE> <array_name> <Operator> (...)
+# and causes the extractor to create an array
+# named <array_name> with offset, in the generated AML,
+# of an object of a given type in the following <Operator>.
+# 
+# A directive must fit on a single code line.
+# 
+# Object type in AML is verified, a mismatch causes a build failure.
+# 
+# Directives and operators currently supported are:
+# ACPI_EXTRACT_NAME_DWORD_CONST - extract a Dword Const object from Name()
+# ACPI_EXTRACT_NAME_WORD_CONST - extract a Word Const object from Name()
+# ACPI_EXTRACT_NAME_BYTE_CONST - extract a Byte Const object from Name()
+# ACPI_EXTRACT_METHOD_STRING - extract a NameString from Method()
+# ACPI_EXTRACT_NAME_STRING - extract a NameString from Name()
+# ACPI_EXTRACT_PROCESSOR_START - start of Processor() block
+# ACPI_EXTRACT_PROCESSOR_STRING - extract a NameString from Processor()
+# ACPI_EXTRACT_PROCESSOR_END - offset at last byte of Processor() + 1
+# ACPI_EXTRACT_PKG_START - start of Package block
+#
+# ACPI_EXTRACT_ALL_CODE - create an array storing the generated AML bytecode
+# 
+# ACPI_EXTRACT is not allowed anywhere else in code, except in comments.
+
+import re;
+import sys;
+import fileinput;
+
+aml = []
+asl = []
+output = {}
+debug = ""
+
+class asl_line:
+    line = None
+    lineno = None
+    aml_offset = None
+
+def die(diag):
+    sys.stderr.write("Error: %s; %s\n" % (diag, debug))
+    sys.exit(1)
+    
+#Store an ASL command, matching AML offset, and input line (for debugging)
+def add_asl(lineno, line):
+    l = asl_line()
+    l.line = line
+    l.lineno = lineno
+    l.aml_offset = len(aml)
+    asl.append(l)
+
+#Store an AML byte sequence
+#Verify that offset output by iasl matches # of bytes so far
+def add_aml(offset, line):
+    o = int(offset, 16);
+    # Sanity check: offset must match size of code so far
+    if (o != len(aml)):
+        die("Offset 0x%x != 0x%x" % (o, len(aml)))
+    # Strip any trailing dots and ASCII dump after "
+    line = re.sub(r'\s*\.*\s*".*$',"", line)
+    # Strip traling whitespace
+    line = re.sub(r'\s+$',"", line)
+    # Strip leading whitespace
+    line = re.sub(r'^\s+',"", line)
+    # Split on whitespace
+    code = re.split(r'\s+', line)
+    for c in code:
+        # Require a legal hex number, two digits
+        if (not(re.search(r'^[0-9A-Fa-f][0-9A-Fa-f]$', c))):
+            die("Unexpected octet %s" % c);
+        aml.append(int(c, 16));
+
+# Process aml bytecode array, decoding AML
+def aml_pkglen_bytes(offset):
+    # PkgLength can be multibyte. Bits 8-7 give the # of extra bytes.
+    pkglenbytes = aml[offset] >> 6;
+    return pkglenbytes + 1
+
+def aml_pkglen(offset):
+    pkgstart = offset
+    pkglenbytes = aml_pkglen_bytes(offset)
+    pkglen = aml[offset] & 0x3F
+    # If multibyte, first nibble only uses bits 0-3
+    if ((pkglenbytes > 0) and (pkglen & 0x30)):
+        die("PkgLen bytes 0x%x but first nibble 0x%x expected 0x0X" %
+            (pkglen, pkglen))
+    offset += 1
+    pkglenbytes -= 1
+    for i in range(pkglenbytes):
+        pkglen |= aml[offset + i] << (i * 8 + 4)
+    if (len(aml) < pkgstart + pkglen):
+        die("PckgLen 0x%x at offset 0x%x exceeds AML size 0x%x" %
+            (pkglen, offset, len(aml)))
+    return pkglen
+
+# Given method offset, find its NameString offset
+def aml_method_string(offset):
+    #0x14 MethodOp PkgLength NameString MethodFlags TermList
+    if (aml[offset] != 0x14):
+        die( "Method offset 0x%x: expected 0x14 actual 0x%x" %
+             (offset, aml[offset]));
+    offset += 1;
+    pkglenbytes = aml_pkglen_bytes(offset)
+    offset += pkglenbytes;
+    return offset;
+
+# Given name offset, find its NameString offset
+def aml_name_string(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x08):
+        die( "Name offset 0x%x: expected 0x08 actual 0x%x" %
+             (offset, aml[offset]));
+    offset += 1
+    # Block Name Modifier. Skip it.
+    if (aml[offset] == 0x5c or aml[offset] == 0x5e):
+        offset += 1
+    return offset;
+
+# Given data offset, find dword const offset
+def aml_data_dword_const(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x0C):
+        die( "Name offset 0x%x: expected 0x0C actual 0x%x" %
+             (offset, aml[offset]));
+    return offset + 1;
+
+# Given data offset, find word const offset
+def aml_data_word_const(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x0B):
+        die( "Name offset 0x%x: expected 0x0B actual 0x%x" %
+             (offset, aml[offset]));
+    return offset + 1;
+
+# Given data offset, find byte const offset
+def aml_data_byte_const(offset):
+    #0x08 NameOp NameString DataRef
+    if (aml[offset] != 0x0A):
+        die( "Name offset 0x%x: expected 0x0A actual 0x%x" %
+             (offset, aml[offset]));
+    return offset + 1;
+
+# Given name offset, find dword const offset
+def aml_name_dword_const(offset):
+    return aml_data_dword_const(aml_name_string(offset) + 4)
+
+# Given name offset, find word const offset
+def aml_name_word_const(offset):
+    return aml_data_word_const(aml_name_string(offset) + 4)
+
+# Given name offset, find byte const offset
+def aml_name_byte_const(offset):
+    return aml_data_byte_const(aml_name_string(offset) + 4)
+
+def aml_processor_start(offset):
+    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
+    if ((aml[offset] != 0x5B) or (aml[offset + 1] != 0x83)):
+        die( "Name offset 0x%x: expected 0x5B 0x83 actual 0x%x 0x%x" %
+             (offset, aml[offset], aml[offset + 1]));
+    return offset
+
+def aml_processor_string(offset):
+    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
+    start = aml_processor_start(offset)
+    offset += 2
+    pkglenbytes = aml_pkglen_bytes(offset)
+    offset += pkglenbytes
+    return offset
+
+def aml_processor_end(offset):
+    start = aml_processor_start(offset)
+    offset += 2
+    pkglenbytes = aml_pkglen_bytes(offset)
+    pkglen = aml_pkglen(offset)
+    return offset + pkglen
+
+def aml_package_start(offset):
+    offset = aml_name_string(offset) + 4
+    # 0x12 PkgLength NumElements PackageElementList
+    if (aml[offset] != 0x12):
+        die( "Name offset 0x%x: expected 0x12 actual 0x%x" %
+             (offset, aml[offset]));
+    offset += 1
+    return offset + aml_pkglen_bytes(offset) + 1
+
+lineno = 0
+for line in fileinput.input():
+    # Strip trailing newline
+    line = line.rstrip();
+    # line number and debug string to output in case of errors
+    lineno = lineno + 1
+    debug = "input line %d: %s" % (lineno, line)
+    #ASL listing: space, then line#, then ...., then code
+    pasl = re.compile('^\s+([0-9]+)\.\.\.\.\s*')
+    m = pasl.search(line)
+    if (m):
+        add_asl(lineno, pasl.sub("", line));
+    # AML listing: offset in hex, then ...., then code
+    paml = re.compile('^([0-9A-Fa-f]+)\.\.\.\.\s*')
+    m = paml.search(line)
+    if (m):
+        add_aml(m.group(1), paml.sub("", line))
+
+# Now go over code
+# Track AML offset of a previous non-empty ASL command
+prev_aml_offset = -1
+for i in range(len(asl)):
+    debug = "input line %d: %s" % (asl[i].lineno, asl[i].line)
+
+    l = asl[i].line
+
+    # skip if not an extract directive
+    a = len(re.findall(r'ACPI_EXTRACT', l))
+    if (not a):
+        # If not empty, store AML offset. Will be used for sanity checks
+        # IASL seems to put {}. at random places in the listing.
+        # Ignore any non-words for the purpose of this test.
+        m = re.search(r'\w+', l)
+        if (m):
+                prev_aml_offset = asl[i].aml_offset
+        continue
+
+    if (a > 1):
+        die("Expected at most one ACPI_EXTRACT per line, actual %d" % a)
+
+    mext = re.search(r'''
+                      ^\s* # leading whitespace
+                      /\*\s* # start C comment
+                      (ACPI_EXTRACT_\w+) # directive: group(1)
+                      \s+ # whitspace separates directive from array name
+                      (\w+) # array name: group(2)
+                      \s*\*/ # end of C comment
+                      \s*$ # trailing whitespace
+                      ''', l, re.VERBOSE)
+    if (not mext):
+        die("Stray ACPI_EXTRACT in input")
+
+    # previous command must have produced some AML,
+    # otherwise we are in a middle of a block
+    if (prev_aml_offset == asl[i].aml_offset):
+        die("ACPI_EXTRACT directive in the middle of a block")
+
+    directive = mext.group(1)
+    array = mext.group(2)
+    offset = asl[i].aml_offset
+
+    if (directive == "ACPI_EXTRACT_ALL_CODE"):
+        if array in output:
+            die("%s directive used more than once" % directive)
+        output[array] = aml
+        continue
+    if (directive == "ACPI_EXTRACT_NAME_DWORD_CONST"):
+        offset = aml_name_dword_const(offset)
+    elif (directive == "ACPI_EXTRACT_NAME_WORD_CONST"):
+        offset = aml_name_word_const(offset)
+    elif (directive == "ACPI_EXTRACT_NAME_BYTE_CONST"):
+        offset = aml_name_byte_const(offset)
+    elif (directive == "ACPI_EXTRACT_NAME_STRING"):
+        offset = aml_name_string(offset)
+    elif (directive == "ACPI_EXTRACT_METHOD_STRING"):
+        offset = aml_method_string(offset)
+    elif (directive == "ACPI_EXTRACT_PROCESSOR_START"):
+        offset = aml_processor_start(offset)
+    elif (directive == "ACPI_EXTRACT_PROCESSOR_STRING"):
+        offset = aml_processor_string(offset)
+    elif (directive == "ACPI_EXTRACT_PROCESSOR_END"):
+        offset = aml_processor_end(offset)
+    elif (directive == "ACPI_EXTRACT_PKG_START"):
+        offset = aml_package_start(offset)
+    else:
+        die("Unsupported directive %s" % directive)
+
+    if array not in output:
+        output[array] = []
+    output[array].append(offset)
+
+debug = "at end of file"
+
+def get_value_type(maxvalue):
+    #Use type large enough to fit the table
+    if (maxvalue >= 0x10000):
+            return "int"
+    elif (maxvalue >= 0x100):
+            return "short"
+    else:
+            return "char"
+
+# Pretty print output
+for array in output.keys():
+    otype = get_value_type(max(output[array]))
+    odata = []
+    for value in output[array]:
+        odata.append("0x%x" % value)
+    sys.stdout.write("unsigned %s %s[] = {\n" % (otype, array))
+    sys.stdout.write(",\n".join(odata))
+    sys.stdout.write('\n};\n');
diff --git a/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py b/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py
new file mode 100644
index 0000000..4ae364e
--- /dev/null
+++ b/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py
@@ -0,0 +1,41 @@
+#!/usr/bin/python
+# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+# Read a preprocessed ASL listing and put each ACPI_EXTRACT
+# directive in a comment, to make iasl skip it.
+# We also put each directive on a new line, the machinery
+# in tools/acpi_extract.py requires this.
+
+import re;
+import sys;
+import fileinput;
+
+def die(diag):
+    sys.stderr.write("Error: %s\n" % (diag))
+    sys.exit(1)
+
+# Note: () around pattern make split return matched string as part of list
+psplit = re.compile(r''' (
+                          \b # At word boundary
+                          ACPI_EXTRACT_\w+ # directive
+                          \s+ # some whitespace
+                          \w+ # array name
+                         )''', re.VERBOSE);
+
+lineno = 0
+for line in fileinput.input():
+    # line number and debug string to output in case of errors
+    lineno = lineno + 1
+    debug = "input line %d: %s" % (lineno, line.rstrip())
+
+    s = psplit.split(line);
+    # The way split works, each odd item is the matching ACPI_EXTRACT directive.
+    # Put each in a comment, and on a line by itself.
+    for i in range(len(s)):
+        if (i % 2):
+            sys.stdout.write("\n/* %s */\n" % s[i])
+        else:
+            sys.stdout.write(s[i])
+
-- 
1.8.3.4


[-- Attachment #3: Type: text/plain, Size: 126 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [Xen-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
  2013-10-24 12:17                 ` [Qemu-devel] [Xen-devel] " Gonglei (Arei)
@ 2013-10-24 12:57                   ` Fabio Fantoni
  2013-10-24 13:16                     ` [Qemu-devel] " Gonglei (Arei)
  2013-10-24 13:16                     ` [Qemu-devel] [Xen-devel] " Gonglei (Arei)
  2013-10-24 12:57                   ` [Qemu-devel] " Fabio Fantoni
                                     ` (2 subsequent siblings)
  3 siblings, 2 replies; 38+ messages in thread
From: Fabio Fantoni @ 2013-10-24 12:57 UTC (permalink / raw)
  To: Gonglei (Arei), Jan Beulich
  Cc: Yanqiangjun, Ian Campbell, Hanweidong (Randy),
	Markus Armbruster, Stefano Stabellini, Luonengjun, qemu-devel,
	xen-devel, anthony.perard, Gaowei (UVP), Huangweidong (Hardware)

Il 24/10/2013 14:17, Gonglei (Arei) ha scritto:
>> -----Original Message-----
>> From: Jan Beulich [mailto:JBeulich@suse.com]
>> Sent: Tuesday, October 22, 2013 4:06 PM
>> To: Gonglei (Arei)
>> Cc: anthony.perard@citrix.com; Ian Campbell; Stefano Stabellini; Gaowei (UVP);
>> Hanweidong (Randy); Huangweidong (Hardware); Luonengjun; Yanqiangjun;
>> xen-devel@lists.xen.org; Fabio Fantoni; qemu-devel@nongnu.org; Markus
>> Armbruster
>> Subject: RE: [Qemu-devel] [Xen-devel] Hvmloader: Modify ACPI to only supply
>> _EJ0 methods for PCIslots that support hotplug by runtime patching
>>
>>>>> On 22.10.13 at 06:08, "Gonglei (Arei)" <arei.gonglei@huawei.com> wrote:
>>> Hi, guys. The new patch has been modified based on the principles you
>>> suggested, thank you so much.
>>> Last time I test the patch based on the codes of 4.3.0.
>>> This time, I found that the system based on the codes of trunk causes the VM
>>> reboot again and again, which I have not found out the reason.
>>> So i can not test the patch based on the codes of trunk (details in
>>> EJ0_ACPI_PCI_Hotplug.patch)..
>> I'm afraid we will need you to figure out that problem first, and
>> then do the verification on -unstable. Even if the code shouldn't
>> be that different from 4.3, we still don't want to apply completely
>> untested stuff.
> Hi, Jan. We found that the reason that we used a wrong seabios PATH, and the hvmloader can't load the bios.bin.
> So the VM restart again and again after we start it. That's our fault.
>
> Now I test the patch based on the codes of trunk, which works well.
> The patch has been modified after your suggestion.
> The patch works well with upstream qemu and doesn't affect the system with traditional qemu.
>
>>
>>> --- a/tools/firmware/hvmloader/ovmf.c
>>> +++ b/tools/firmware/hvmloader/ovmf.c
>>> @@ -79,7 +79,11 @@ static void ovmf_acpi_build_tables(void)
>>>           .dsdt_anycpu = dsdt_anycpu,
>>>           .dsdt_anycpu_len = dsdt_anycpu_len,
>>>           .dsdt_15cpu = NULL,
>>> -        .dsdt_15cpu_len = 0
>>> +        .dsdt_15cpu_len = 0,
>>> +        .aml_ej0_name = NULL,
>>> +        .aml_adr_dword = NULL,
>>> +        .aml_ej0_name_len = 0,
>>> +        .aml_adr_dword_len = 0,
>> I don't see why you're adding these.
>>
> Insurance purposes is that just initialize the struct.
>
> Signed-off-by: Gaowei <gao.gaowei@huawei.com>
> Signed-off-by: gonglei <arei.gonglei@huawei.com>

Tested-by: Fabio Fantoni <fabio.fantoni@m2r.biz>

Tested on xen unstable with qemu 1.6.1, no problem found for now.
Only one question: this patch remove hotplug only from essentials pci 
device, right?
On windows 7 hotplug continues to show: virtio-serial driver, xen pci 
device driver and hd audio.

Thanks for any reply.

> ---
>   tools/firmware/hvmloader/acpi/Makefile             |  37 ++-
>   tools/firmware/hvmloader/acpi/acpi2_0.h            |   4 +
>   tools/firmware/hvmloader/acpi/build.c              |  21 +-
>   tools/firmware/hvmloader/acpi/dsdt.asl             |   1 +
>   tools/firmware/hvmloader/acpi/mk_dsdt.c            |   2 +
>   tools/firmware/hvmloader/ovmf.c                    |   6 +-
>   tools/firmware/hvmloader/rombios.c                 |   4 +
>   tools/firmware/hvmloader/seabios.c                 |   8 +
>   tools/firmware/hvmloader/tools/acpi_extract.py     | 308 +++++++++++++++++++++
>   .../hvmloader/tools/acpi_extract_preprocess.py     |  41 +++
>   10 files changed, 419 insertions(+), 13 deletions(-)
>   create mode 100644 tools/firmware/hvmloader/tools/acpi_extract.py
>   create mode 100644 tools/firmware/hvmloader/tools/acpi_extract_preprocess.py
>
> diff --git a/tools/firmware/hvmloader/acpi/Makefile b/tools/firmware/hvmloader/acpi/Makefile
> index 2c50851..b96e058 100644
> --- a/tools/firmware/hvmloader/acpi/Makefile
> +++ b/tools/firmware/hvmloader/acpi/Makefile
> @@ -24,30 +24,45 @@ OBJS  = $(patsubst %.c,%.o,$(C_SRC))
>   CFLAGS += $(CFLAGS_xeninclude)
>   
>   vpath iasl $(PATH)
> +
> +.DELETE_ON_ERROR: $(filter dsdt_%.c,$(C_SRC))
> +
>   all: acpi.a
>   
>   ssdt_s3.h ssdt_s4.h ssdt_pm.h ssdt_tpm.h: %.h: %.asl iasl
>   	iasl -vs -p $* -tc $<
> -	sed -e 's/AmlCode/$*/g' $*.hex >$@
> +	sed -e 's/AmlCode/$*/g' $*.hex > $@.tmp
> +	$(call move-if-changed,$@.tmp $@)
>   	rm -f $*.hex $*.aml
>   
>   mk_dsdt: mk_dsdt.c
>   	$(HOSTCC) $(HOSTCFLAGS) $(CFLAGS_xeninclude) -o $@ mk_dsdt.c
>   
>   dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
> -	awk 'NR > 1 {print s} {s=$$0}' $< > $@
> -	./mk_dsdt --dm-version qemu-xen >> $@
> +	awk 'NR > 1 {print s} {s=$$0}' $< > $@.tmp
> +	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@.tmp
> +	./mk_dsdt --dm-version qemu-xen >> $@.tmp
> +	sed -i 's/aml_ej0_name/dsdt_anycpu_qemu_xen_aml_ej0_name/g' $@.tmp
> +	sed -i 's/aml_adr_dword/dsdt_anycpu_qemu_xen_aml_adr_dword/g' $@.tmp
> +	$(call move-if-changed,$@.tmp $@)
>   
>   # NB. awk invocation is a portable alternative to 'head -n -1'
>   dsdt_%cpu.asl: dsdt.asl mk_dsdt
> -	awk 'NR > 1 {print s} {s=$$0}' $< > $@
> -	./mk_dsdt --maxcpu $*  >> $@
> +	awk 'NR > 1 {print s} {s=$$0}' $< > $@.tmp
> +	sed -i 's/AmlCode/dsdt_$*cpu/g' $@.tmp
> +	./mk_dsdt --maxcpu $*  >> $@.tmp
> +	$(call move-if-changed,$@.tmp $@)
>   
> -$(filter dsdt_%.c,$(C_SRC)): %.c: iasl %.asl
> -	iasl -vs -p $* -tc $*.asl
> -	sed -e 's/AmlCode/$*/g' $*.hex >$@
> -	echo "int $*_len=sizeof($*);" >>$@
> -	rm -f $*.aml $*.hex
> +$(filter dsdt_%.c,$(C_SRC)): %.c: %.asl iasl
> +	cpp -P $< > $<.i.orig
> +	$(PYTHON) ../tools/acpi_extract_preprocess.py $<.i.orig > $<.i
> +	iasl -vs -l -tc -p $* $<.i
> +	$(PYTHON) ../tools/acpi_extract.py $*.lst > $@.tmp
> +	echo "int $*_len=sizeof($*);" >> $@.tmp
> +	if grep -q "$*_aml_ej0_name" $@.tmp; then echo "int $*_aml_ej0_name_len=sizeof($*_aml_ej0_name);" >> $@.tmp; fi
> +	if grep -q "$*_aml_adr_dword" $@.tmp; then echo "int $*_aml_adr_dword_len=sizeof($*_aml_adr_dword);" >> $@.tmp; fi
> +	$(call move-if-changed,$@.tmp $@)
> +	rm -f $*.aml $*.hex $*.asl.i.orig $*.asl.i $*.lst
>   
>   iasl:
>   	@echo
> @@ -64,7 +79,7 @@ acpi.a: $(OBJS)
>   
>   clean:
>   	rm -rf *.a *.o $(IASL_VER) $(IASL_VER).tar.gz $(DEPS)
> -	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl
> +	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl *.asl.i *.asl.i.orig *.lst *.tmp
>   
>   install: all
>   
> diff --git a/tools/firmware/hvmloader/acpi/acpi2_0.h b/tools/firmware/hvmloader/acpi/acpi2_0.h
> index 7b22d80..4ba3957 100644
> --- a/tools/firmware/hvmloader/acpi/acpi2_0.h
> +++ b/tools/firmware/hvmloader/acpi/acpi2_0.h
> @@ -396,6 +396,10 @@ struct acpi_config {
>       int dsdt_anycpu_len;
>       unsigned char *dsdt_15cpu;
>       int dsdt_15cpu_len;
> +    unsigned short *aml_ej0_name;
> +    unsigned short *aml_adr_dword;
> +    int aml_ej0_name_len;
> +    int aml_adr_dword_len;
>   };
>   
>   void acpi_build_tables(struct acpi_config *config, unsigned int physical);
> diff --git a/tools/firmware/hvmloader/acpi/build.c b/tools/firmware/hvmloader/acpi/build.c
> index f1dd3f0..7eb21d3 100644
> --- a/tools/firmware/hvmloader/acpi/build.c
> +++ b/tools/firmware/hvmloader/acpi/build.c
> @@ -29,6 +29,7 @@
>   
>   #define align16(sz)        (((sz) + 15) & ~15)
>   #define fixed_strcpy(d, s) strncpy((d), (s), sizeof(d))
> +#define PCI_RMV_BASE 0xae0c
>   
>   extern struct acpi_20_rsdp Rsdp;
>   extern struct acpi_20_rsdt Rsdt;
> @@ -404,6 +405,7 @@ void acpi_build_tables(struct acpi_config *config, unsigned int physical)
>       unsigned char       *dsdt;
>       unsigned long        secondary_tables[ACPI_MAX_SECONDARY_TABLES];
>       int                  nr_secondaries, i;
> +    unsigned int rmvc_pcrm = 0;
>   
>       /* Allocate and initialise the acpi info area. */
>       mem_hole_populate_ram(ACPI_INFO_PHYSICAL_ADDRESS >> PAGE_SHIFT, 1);
> @@ -440,7 +442,24 @@ void acpi_build_tables(struct acpi_config *config, unsigned int physical)
>           memcpy(dsdt, config->dsdt_anycpu, config->dsdt_anycpu_len);
>           nr_processor_objects = HVM_MAX_VCPUS;
>       }
> -
> +    if(config->aml_adr_dword_len && config->aml_ej0_name_len &&
> +        (config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]) == config->aml_ej0_name_len/sizeof(config->aml_ej0_name[0])))
> +    {
> +        rmvc_pcrm = inl(PCI_RMV_BASE);
> +        for(i = 0;  i < config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]); i ++)
> +        {
> +            /* Slot is in byte 2 in _ADR */
> +            unsigned char slot = dsdt[config->aml_adr_dword[i] + 2] & 0x1F;
> +            /* Sanity check */
> +            if (memcmp(dsdt + config->aml_ej0_name[i], "_EJ0", 4)) {
> +                printf("Method '_EJ0' can not be found for pci slot %d\n", slot);
> +                return;
> +            }
> +            if (!(rmvc_pcrm & (0x1 << slot))) {
> +                memcpy(dsdt + config->aml_ej0_name[i], "EJ0_", 4);
> +            }
> +        }
> +    }
>       /*
>        * N.B. ACPI 1.0 operating systems may not handle FADT with revision 2
>        * or above properly, notably Windows 2000, which tries to copy FADT
> diff --git a/tools/firmware/hvmloader/acpi/dsdt.asl b/tools/firmware/hvmloader/acpi/dsdt.asl
> index 247a8ad..1e7695b 100644
> --- a/tools/firmware/hvmloader/acpi/dsdt.asl
> +++ b/tools/firmware/hvmloader/acpi/dsdt.asl
> @@ -16,6 +16,7 @@
>    * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
>    * Place - Suite 330, Boston, MA 02111-1307 USA.
>    */
> +ACPI_EXTRACT_ALL_CODE AmlCode
>   
>   DefinitionBlock ("DSDT.aml", "DSDT", 2, "Xen", "HVM", 0)
>   {
> diff --git a/tools/firmware/hvmloader/acpi/mk_dsdt.c b/tools/firmware/hvmloader/acpi/mk_dsdt.c
> index 996f30b..4180801 100644
> --- a/tools/firmware/hvmloader/acpi/mk_dsdt.c
> +++ b/tools/firmware/hvmloader/acpi/mk_dsdt.c
> @@ -368,7 +368,9 @@ int main(int argc, char **argv)
>           /* hotplug_slot */
>           for (slot = 1; slot <= 31; slot++) {
>               push_block("Device", "S%i", slot); {
> +                printf("ACPI_EXTRACT_NAME_DWORD_CONST aml_adr_dword\n");
>                   stmt("Name", "_ADR, %#06x0000", slot);
> +                printf("ACPI_EXTRACT_METHOD_STRING aml_ej0_name\n");
>                   push_block("Method", "_EJ0,1"); {
>                       stmt("Store", "ShiftLeft(1, %#06x), B0EJ", slot);
>                       stmt("Return", "0x0");
> diff --git a/tools/firmware/hvmloader/ovmf.c b/tools/firmware/hvmloader/ovmf.c
> index ee4cbbf..27ff0b5 100644
> --- a/tools/firmware/hvmloader/ovmf.c
> +++ b/tools/firmware/hvmloader/ovmf.c
> @@ -79,7 +79,11 @@ static void ovmf_acpi_build_tables(void)
>           .dsdt_anycpu = dsdt_anycpu,
>           .dsdt_anycpu_len = dsdt_anycpu_len,
>           .dsdt_15cpu = NULL,
> -        .dsdt_15cpu_len = 0
> +        .dsdt_15cpu_len = 0,
> +        .aml_ej0_name = NULL,
> +        .aml_adr_dword = NULL,
> +        .aml_ej0_name_len = 0,
> +        .aml_adr_dword_len = 0,
>       };
>   
>       acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
> diff --git a/tools/firmware/hvmloader/rombios.c b/tools/firmware/hvmloader/rombios.c
> index 810bd24..803c9fa 100644
> --- a/tools/firmware/hvmloader/rombios.c
> +++ b/tools/firmware/hvmloader/rombios.c
> @@ -179,6 +179,10 @@ static void rombios_acpi_build_tables(void)
>           .dsdt_anycpu_len = dsdt_anycpu_len,
>           .dsdt_15cpu = dsdt_15cpu,
>           .dsdt_15cpu_len = dsdt_15cpu_len,
> +        .aml_ej0_name = NULL,
> +        .aml_adr_dword = NULL,
> +        .aml_ej0_name_len = 0,
> +        .aml_adr_dword_len = 0,
>       };
>   
>       acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
> diff --git a/tools/firmware/hvmloader/seabios.c b/tools/firmware/hvmloader/seabios.c
> index dd7dfbe..ca01d27 100644
> --- a/tools/firmware/hvmloader/seabios.c
> +++ b/tools/firmware/hvmloader/seabios.c
> @@ -33,6 +33,10 @@
>   
>   extern unsigned char dsdt_anycpu_qemu_xen[];
>   extern int dsdt_anycpu_qemu_xen_len;
> +extern unsigned short dsdt_anycpu_qemu_xen_aml_ej0_name[];
> +extern unsigned short dsdt_anycpu_qemu_xen_aml_adr_dword[];
> +extern int dsdt_anycpu_qemu_xen_aml_ej0_name_len;
> +extern int dsdt_anycpu_qemu_xen_aml_adr_dword_len;
>   
>   struct seabios_info {
>       char signature[14]; /* XenHVMSeaBIOS\0 */
> @@ -99,6 +103,10 @@ static void seabios_acpi_build_tables(void)
>           .dsdt_anycpu_len = dsdt_anycpu_qemu_xen_len,
>           .dsdt_15cpu = NULL,
>           .dsdt_15cpu_len = 0,
> +        .aml_ej0_name = dsdt_anycpu_qemu_xen_aml_ej0_name,
> +        .aml_adr_dword = dsdt_anycpu_qemu_xen_aml_adr_dword,
> +        .aml_ej0_name_len = dsdt_anycpu_qemu_xen_aml_ej0_name_len,
> +        .aml_adr_dword_len = dsdt_anycpu_qemu_xen_aml_adr_dword_len,
>       };
>   
>       acpi_build_tables(&config, rsdp);
> diff --git a/tools/firmware/hvmloader/tools/acpi_extract.py b/tools/firmware/hvmloader/tools/acpi_extract.py
> new file mode 100644
> index 0000000..4fa51f7
> --- /dev/null
> +++ b/tools/firmware/hvmloader/tools/acpi_extract.py
> @@ -0,0 +1,308 @@
> +#!/usr/bin/python
> +# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
> +#
> +# This file may be distributed under the terms of the GNU GPLv3 license.
> +
> +# Process mixed ASL/AML listing (.lst file) produced by iasl -l
> +# Locate and execute ACPI_EXTRACT directives, output offset info
> +#
> +# Documentation of ACPI_EXTRACT_* directive tags:
> +#
> +# These directive tags output offset information from AML for BIOS runtime
> +# table generation.
> +# Each directive is of the form:
> +# ACPI_EXTRACT_<TYPE> <array_name> <Operator> (...)
> +# and causes the extractor to create an array
> +# named <array_name> with offset, in the generated AML,
> +# of an object of a given type in the following <Operator>.
> +#
> +# A directive must fit on a single code line.
> +#
> +# Object type in AML is verified, a mismatch causes a build failure.
> +#
> +# Directives and operators currently supported are:
> +# ACPI_EXTRACT_NAME_DWORD_CONST - extract a Dword Const object from Name()
> +# ACPI_EXTRACT_NAME_WORD_CONST - extract a Word Const object from Name()
> +# ACPI_EXTRACT_NAME_BYTE_CONST - extract a Byte Const object from Name()
> +# ACPI_EXTRACT_METHOD_STRING - extract a NameString from Method()
> +# ACPI_EXTRACT_NAME_STRING - extract a NameString from Name()
> +# ACPI_EXTRACT_PROCESSOR_START - start of Processor() block
> +# ACPI_EXTRACT_PROCESSOR_STRING - extract a NameString from Processor()
> +# ACPI_EXTRACT_PROCESSOR_END - offset at last byte of Processor() + 1
> +# ACPI_EXTRACT_PKG_START - start of Package block
> +#
> +# ACPI_EXTRACT_ALL_CODE - create an array storing the generated AML bytecode
> +#
> +# ACPI_EXTRACT is not allowed anywhere else in code, except in comments.
> +
> +import re;
> +import sys;
> +import fileinput;
> +
> +aml = []
> +asl = []
> +output = {}
> +debug = ""
> +
> +class asl_line:
> +    line = None
> +    lineno = None
> +    aml_offset = None
> +
> +def die(diag):
> +    sys.stderr.write("Error: %s; %s\n" % (diag, debug))
> +    sys.exit(1)
> +
> +#Store an ASL command, matching AML offset, and input line (for debugging)
> +def add_asl(lineno, line):
> +    l = asl_line()
> +    l.line = line
> +    l.lineno = lineno
> +    l.aml_offset = len(aml)
> +    asl.append(l)
> +
> +#Store an AML byte sequence
> +#Verify that offset output by iasl matches # of bytes so far
> +def add_aml(offset, line):
> +    o = int(offset, 16);
> +    # Sanity check: offset must match size of code so far
> +    if (o != len(aml)):
> +        die("Offset 0x%x != 0x%x" % (o, len(aml)))
> +    # Strip any trailing dots and ASCII dump after "
> +    line = re.sub(r'\s*\.*\s*".*$',"", line)
> +    # Strip traling whitespace
> +    line = re.sub(r'\s+$',"", line)
> +    # Strip leading whitespace
> +    line = re.sub(r'^\s+',"", line)
> +    # Split on whitespace
> +    code = re.split(r'\s+', line)
> +    for c in code:
> +        # Require a legal hex number, two digits
> +        if (not(re.search(r'^[0-9A-Fa-f][0-9A-Fa-f]$', c))):
> +            die("Unexpected octet %s" % c);
> +        aml.append(int(c, 16));
> +
> +# Process aml bytecode array, decoding AML
> +def aml_pkglen_bytes(offset):
> +    # PkgLength can be multibyte. Bits 8-7 give the # of extra bytes.
> +    pkglenbytes = aml[offset] >> 6;
> +    return pkglenbytes + 1
> +
> +def aml_pkglen(offset):
> +    pkgstart = offset
> +    pkglenbytes = aml_pkglen_bytes(offset)
> +    pkglen = aml[offset] & 0x3F
> +    # If multibyte, first nibble only uses bits 0-3
> +    if ((pkglenbytes > 0) and (pkglen & 0x30)):
> +        die("PkgLen bytes 0x%x but first nibble 0x%x expected 0x0X" %
> +            (pkglen, pkglen))
> +    offset += 1
> +    pkglenbytes -= 1
> +    for i in range(pkglenbytes):
> +        pkglen |= aml[offset + i] << (i * 8 + 4)
> +    if (len(aml) < pkgstart + pkglen):
> +        die("PckgLen 0x%x at offset 0x%x exceeds AML size 0x%x" %
> +            (pkglen, offset, len(aml)))
> +    return pkglen
> +
> +# Given method offset, find its NameString offset
> +def aml_method_string(offset):
> +    #0x14 MethodOp PkgLength NameString MethodFlags TermList
> +    if (aml[offset] != 0x14):
> +        die( "Method offset 0x%x: expected 0x14 actual 0x%x" %
> +             (offset, aml[offset]));
> +    offset += 1;
> +    pkglenbytes = aml_pkglen_bytes(offset)
> +    offset += pkglenbytes;
> +    return offset;
> +
> +# Given name offset, find its NameString offset
> +def aml_name_string(offset):
> +    #0x08 NameOp NameString DataRef
> +    if (aml[offset] != 0x08):
> +        die( "Name offset 0x%x: expected 0x08 actual 0x%x" %
> +             (offset, aml[offset]));
> +    offset += 1
> +    # Block Name Modifier. Skip it.
> +    if (aml[offset] == 0x5c or aml[offset] == 0x5e):
> +        offset += 1
> +    return offset;
> +
> +# Given data offset, find dword const offset
> +def aml_data_dword_const(offset):
> +    #0x08 NameOp NameString DataRef
> +    if (aml[offset] != 0x0C):
> +        die( "Name offset 0x%x: expected 0x0C actual 0x%x" %
> +             (offset, aml[offset]));
> +    return offset + 1;
> +
> +# Given data offset, find word const offset
> +def aml_data_word_const(offset):
> +    #0x08 NameOp NameString DataRef
> +    if (aml[offset] != 0x0B):
> +        die( "Name offset 0x%x: expected 0x0B actual 0x%x" %
> +             (offset, aml[offset]));
> +    return offset + 1;
> +
> +# Given data offset, find byte const offset
> +def aml_data_byte_const(offset):
> +    #0x08 NameOp NameString DataRef
> +    if (aml[offset] != 0x0A):
> +        die( "Name offset 0x%x: expected 0x0A actual 0x%x" %
> +             (offset, aml[offset]));
> +    return offset + 1;
> +
> +# Given name offset, find dword const offset
> +def aml_name_dword_const(offset):
> +    return aml_data_dword_const(aml_name_string(offset) + 4)
> +
> +# Given name offset, find word const offset
> +def aml_name_word_const(offset):
> +    return aml_data_word_const(aml_name_string(offset) + 4)
> +
> +# Given name offset, find byte const offset
> +def aml_name_byte_const(offset):
> +    return aml_data_byte_const(aml_name_string(offset) + 4)
> +
> +def aml_processor_start(offset):
> +    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
> +    if ((aml[offset] != 0x5B) or (aml[offset + 1] != 0x83)):
> +        die( "Name offset 0x%x: expected 0x5B 0x83 actual 0x%x 0x%x" %
> +             (offset, aml[offset], aml[offset + 1]));
> +    return offset
> +
> +def aml_processor_string(offset):
> +    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
> +    start = aml_processor_start(offset)
> +    offset += 2
> +    pkglenbytes = aml_pkglen_bytes(offset)
> +    offset += pkglenbytes
> +    return offset
> +
> +def aml_processor_end(offset):
> +    start = aml_processor_start(offset)
> +    offset += 2
> +    pkglenbytes = aml_pkglen_bytes(offset)
> +    pkglen = aml_pkglen(offset)
> +    return offset + pkglen
> +
> +def aml_package_start(offset):
> +    offset = aml_name_string(offset) + 4
> +    # 0x12 PkgLength NumElements PackageElementList
> +    if (aml[offset] != 0x12):
> +        die( "Name offset 0x%x: expected 0x12 actual 0x%x" %
> +             (offset, aml[offset]));
> +    offset += 1
> +    return offset + aml_pkglen_bytes(offset) + 1
> +
> +lineno = 0
> +for line in fileinput.input():
> +    # Strip trailing newline
> +    line = line.rstrip();
> +    # line number and debug string to output in case of errors
> +    lineno = lineno + 1
> +    debug = "input line %d: %s" % (lineno, line)
> +    #ASL listing: space, then line#, then ...., then code
> +    pasl = re.compile('^\s+([0-9]+)\.\.\.\.\s*')
> +    m = pasl.search(line)
> +    if (m):
> +        add_asl(lineno, pasl.sub("", line));
> +    # AML listing: offset in hex, then ...., then code
> +    paml = re.compile('^([0-9A-Fa-f]+)\.\.\.\.\s*')
> +    m = paml.search(line)
> +    if (m):
> +        add_aml(m.group(1), paml.sub("", line))
> +
> +# Now go over code
> +# Track AML offset of a previous non-empty ASL command
> +prev_aml_offset = -1
> +for i in range(len(asl)):
> +    debug = "input line %d: %s" % (asl[i].lineno, asl[i].line)
> +
> +    l = asl[i].line
> +
> +    # skip if not an extract directive
> +    a = len(re.findall(r'ACPI_EXTRACT', l))
> +    if (not a):
> +        # If not empty, store AML offset. Will be used for sanity checks
> +        # IASL seems to put {}. at random places in the listing.
> +        # Ignore any non-words for the purpose of this test.
> +        m = re.search(r'\w+', l)
> +        if (m):
> +                prev_aml_offset = asl[i].aml_offset
> +        continue
> +
> +    if (a > 1):
> +        die("Expected at most one ACPI_EXTRACT per line, actual %d" % a)
> +
> +    mext = re.search(r'''
> +                      ^\s* # leading whitespace
> +                      /\*\s* # start C comment
> +                      (ACPI_EXTRACT_\w+) # directive: group(1)
> +                      \s+ # whitspace separates directive from array name
> +                      (\w+) # array name: group(2)
> +                      \s*\*/ # end of C comment
> +                      \s*$ # trailing whitespace
> +                      ''', l, re.VERBOSE)
> +    if (not mext):
> +        die("Stray ACPI_EXTRACT in input")
> +
> +    # previous command must have produced some AML,
> +    # otherwise we are in a middle of a block
> +    if (prev_aml_offset == asl[i].aml_offset):
> +        die("ACPI_EXTRACT directive in the middle of a block")
> +
> +    directive = mext.group(1)
> +    array = mext.group(2)
> +    offset = asl[i].aml_offset
> +
> +    if (directive == "ACPI_EXTRACT_ALL_CODE"):
> +        if array in output:
> +            die("%s directive used more than once" % directive)
> +        output[array] = aml
> +        continue
> +    if (directive == "ACPI_EXTRACT_NAME_DWORD_CONST"):
> +        offset = aml_name_dword_const(offset)
> +    elif (directive == "ACPI_EXTRACT_NAME_WORD_CONST"):
> +        offset = aml_name_word_const(offset)
> +    elif (directive == "ACPI_EXTRACT_NAME_BYTE_CONST"):
> +        offset = aml_name_byte_const(offset)
> +    elif (directive == "ACPI_EXTRACT_NAME_STRING"):
> +        offset = aml_name_string(offset)
> +    elif (directive == "ACPI_EXTRACT_METHOD_STRING"):
> +        offset = aml_method_string(offset)
> +    elif (directive == "ACPI_EXTRACT_PROCESSOR_START"):
> +        offset = aml_processor_start(offset)
> +    elif (directive == "ACPI_EXTRACT_PROCESSOR_STRING"):
> +        offset = aml_processor_string(offset)
> +    elif (directive == "ACPI_EXTRACT_PROCESSOR_END"):
> +        offset = aml_processor_end(offset)
> +    elif (directive == "ACPI_EXTRACT_PKG_START"):
> +        offset = aml_package_start(offset)
> +    else:
> +        die("Unsupported directive %s" % directive)
> +
> +    if array not in output:
> +        output[array] = []
> +    output[array].append(offset)
> +
> +debug = "at end of file"
> +
> +def get_value_type(maxvalue):
> +    #Use type large enough to fit the table
> +    if (maxvalue >= 0x10000):
> +            return "int"
> +    elif (maxvalue >= 0x100):
> +            return "short"
> +    else:
> +            return "char"
> +
> +# Pretty print output
> +for array in output.keys():
> +    otype = get_value_type(max(output[array]))
> +    odata = []
> +    for value in output[array]:
> +        odata.append("0x%x" % value)
> +    sys.stdout.write("unsigned %s %s[] = {\n" % (otype, array))
> +    sys.stdout.write(",\n".join(odata))
> +    sys.stdout.write('\n};\n');
> diff --git a/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py b/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py
> new file mode 100644
> index 0000000..4ae364e
> --- /dev/null
> +++ b/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py
> @@ -0,0 +1,41 @@
> +#!/usr/bin/python
> +# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
> +#
> +# This file may be distributed under the terms of the GNU GPLv3 license.
> +
> +# Read a preprocessed ASL listing and put each ACPI_EXTRACT
> +# directive in a comment, to make iasl skip it.
> +# We also put each directive on a new line, the machinery
> +# in tools/acpi_extract.py requires this.
> +
> +import re;
> +import sys;
> +import fileinput;
> +
> +def die(diag):
> +    sys.stderr.write("Error: %s\n" % (diag))
> +    sys.exit(1)
> +
> +# Note: () around pattern make split return matched string as part of list
> +psplit = re.compile(r''' (
> +                          \b # At word boundary
> +                          ACPI_EXTRACT_\w+ # directive
> +                          \s+ # some whitespace
> +                          \w+ # array name
> +                         )''', re.VERBOSE);
> +
> +lineno = 0
> +for line in fileinput.input():
> +    # line number and debug string to output in case of errors
> +    lineno = lineno + 1
> +    debug = "input line %d: %s" % (lineno, line.rstrip())
> +
> +    s = psplit.split(line);
> +    # The way split works, each odd item is the matching ACPI_EXTRACT directive.
> +    # Put each in a comment, and on a line by itself.
> +    for i in range(len(s)):
> +        if (i % 2):
> +            sys.stdout.write("\n/* %s */\n" % s[i])
> +        else:
> +            sys.stdout.write(s[i])
> +

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
  2013-10-24 12:17                 ` [Qemu-devel] [Xen-devel] " Gonglei (Arei)
  2013-10-24 12:57                   ` Fabio Fantoni
@ 2013-10-24 12:57                   ` Fabio Fantoni
  2013-10-28  9:38                   ` Jan Beulich
  2013-10-28  9:38                   ` [Qemu-devel] [Xen-devel] " Jan Beulich
  3 siblings, 0 replies; 38+ messages in thread
From: Fabio Fantoni @ 2013-10-24 12:57 UTC (permalink / raw)
  To: Gonglei (Arei), Jan Beulich
  Cc: Yanqiangjun, Ian Campbell, Hanweidong (Randy),
	Markus Armbruster, Stefano Stabellini, Luonengjun, qemu-devel,
	xen-devel, anthony.perard, Gaowei (UVP), Huangweidong (Hardware)

Il 24/10/2013 14:17, Gonglei (Arei) ha scritto:
>> -----Original Message-----
>> From: Jan Beulich [mailto:JBeulich@suse.com]
>> Sent: Tuesday, October 22, 2013 4:06 PM
>> To: Gonglei (Arei)
>> Cc: anthony.perard@citrix.com; Ian Campbell; Stefano Stabellini; Gaowei (UVP);
>> Hanweidong (Randy); Huangweidong (Hardware); Luonengjun; Yanqiangjun;
>> xen-devel@lists.xen.org; Fabio Fantoni; qemu-devel@nongnu.org; Markus
>> Armbruster
>> Subject: RE: [Qemu-devel] [Xen-devel] Hvmloader: Modify ACPI to only supply
>> _EJ0 methods for PCIslots that support hotplug by runtime patching
>>
>>>>> On 22.10.13 at 06:08, "Gonglei (Arei)" <arei.gonglei@huawei.com> wrote:
>>> Hi, guys. The new patch has been modified based on the principles you
>>> suggested, thank you so much.
>>> Last time I test the patch based on the codes of 4.3.0.
>>> This time, I found that the system based on the codes of trunk causes the VM
>>> reboot again and again, which I have not found out the reason.
>>> So i can not test the patch based on the codes of trunk (details in
>>> EJ0_ACPI_PCI_Hotplug.patch)..
>> I'm afraid we will need you to figure out that problem first, and
>> then do the verification on -unstable. Even if the code shouldn't
>> be that different from 4.3, we still don't want to apply completely
>> untested stuff.
> Hi, Jan. We found that the reason that we used a wrong seabios PATH, and the hvmloader can't load the bios.bin.
> So the VM restart again and again after we start it. That's our fault.
>
> Now I test the patch based on the codes of trunk, which works well.
> The patch has been modified after your suggestion.
> The patch works well with upstream qemu and doesn't affect the system with traditional qemu.
>
>>
>>> --- a/tools/firmware/hvmloader/ovmf.c
>>> +++ b/tools/firmware/hvmloader/ovmf.c
>>> @@ -79,7 +79,11 @@ static void ovmf_acpi_build_tables(void)
>>>           .dsdt_anycpu = dsdt_anycpu,
>>>           .dsdt_anycpu_len = dsdt_anycpu_len,
>>>           .dsdt_15cpu = NULL,
>>> -        .dsdt_15cpu_len = 0
>>> +        .dsdt_15cpu_len = 0,
>>> +        .aml_ej0_name = NULL,
>>> +        .aml_adr_dword = NULL,
>>> +        .aml_ej0_name_len = 0,
>>> +        .aml_adr_dword_len = 0,
>> I don't see why you're adding these.
>>
> Insurance purposes is that just initialize the struct.
>
> Signed-off-by: Gaowei <gao.gaowei@huawei.com>
> Signed-off-by: gonglei <arei.gonglei@huawei.com>

Tested-by: Fabio Fantoni <fabio.fantoni@m2r.biz>

Tested on xen unstable with qemu 1.6.1, no problem found for now.
Only one question: this patch remove hotplug only from essentials pci 
device, right?
On windows 7 hotplug continues to show: virtio-serial driver, xen pci 
device driver and hd audio.

Thanks for any reply.

> ---
>   tools/firmware/hvmloader/acpi/Makefile             |  37 ++-
>   tools/firmware/hvmloader/acpi/acpi2_0.h            |   4 +
>   tools/firmware/hvmloader/acpi/build.c              |  21 +-
>   tools/firmware/hvmloader/acpi/dsdt.asl             |   1 +
>   tools/firmware/hvmloader/acpi/mk_dsdt.c            |   2 +
>   tools/firmware/hvmloader/ovmf.c                    |   6 +-
>   tools/firmware/hvmloader/rombios.c                 |   4 +
>   tools/firmware/hvmloader/seabios.c                 |   8 +
>   tools/firmware/hvmloader/tools/acpi_extract.py     | 308 +++++++++++++++++++++
>   .../hvmloader/tools/acpi_extract_preprocess.py     |  41 +++
>   10 files changed, 419 insertions(+), 13 deletions(-)
>   create mode 100644 tools/firmware/hvmloader/tools/acpi_extract.py
>   create mode 100644 tools/firmware/hvmloader/tools/acpi_extract_preprocess.py
>
> diff --git a/tools/firmware/hvmloader/acpi/Makefile b/tools/firmware/hvmloader/acpi/Makefile
> index 2c50851..b96e058 100644
> --- a/tools/firmware/hvmloader/acpi/Makefile
> +++ b/tools/firmware/hvmloader/acpi/Makefile
> @@ -24,30 +24,45 @@ OBJS  = $(patsubst %.c,%.o,$(C_SRC))
>   CFLAGS += $(CFLAGS_xeninclude)
>   
>   vpath iasl $(PATH)
> +
> +.DELETE_ON_ERROR: $(filter dsdt_%.c,$(C_SRC))
> +
>   all: acpi.a
>   
>   ssdt_s3.h ssdt_s4.h ssdt_pm.h ssdt_tpm.h: %.h: %.asl iasl
>   	iasl -vs -p $* -tc $<
> -	sed -e 's/AmlCode/$*/g' $*.hex >$@
> +	sed -e 's/AmlCode/$*/g' $*.hex > $@.tmp
> +	$(call move-if-changed,$@.tmp $@)
>   	rm -f $*.hex $*.aml
>   
>   mk_dsdt: mk_dsdt.c
>   	$(HOSTCC) $(HOSTCFLAGS) $(CFLAGS_xeninclude) -o $@ mk_dsdt.c
>   
>   dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
> -	awk 'NR > 1 {print s} {s=$$0}' $< > $@
> -	./mk_dsdt --dm-version qemu-xen >> $@
> +	awk 'NR > 1 {print s} {s=$$0}' $< > $@.tmp
> +	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@.tmp
> +	./mk_dsdt --dm-version qemu-xen >> $@.tmp
> +	sed -i 's/aml_ej0_name/dsdt_anycpu_qemu_xen_aml_ej0_name/g' $@.tmp
> +	sed -i 's/aml_adr_dword/dsdt_anycpu_qemu_xen_aml_adr_dword/g' $@.tmp
> +	$(call move-if-changed,$@.tmp $@)
>   
>   # NB. awk invocation is a portable alternative to 'head -n -1'
>   dsdt_%cpu.asl: dsdt.asl mk_dsdt
> -	awk 'NR > 1 {print s} {s=$$0}' $< > $@
> -	./mk_dsdt --maxcpu $*  >> $@
> +	awk 'NR > 1 {print s} {s=$$0}' $< > $@.tmp
> +	sed -i 's/AmlCode/dsdt_$*cpu/g' $@.tmp
> +	./mk_dsdt --maxcpu $*  >> $@.tmp
> +	$(call move-if-changed,$@.tmp $@)
>   
> -$(filter dsdt_%.c,$(C_SRC)): %.c: iasl %.asl
> -	iasl -vs -p $* -tc $*.asl
> -	sed -e 's/AmlCode/$*/g' $*.hex >$@
> -	echo "int $*_len=sizeof($*);" >>$@
> -	rm -f $*.aml $*.hex
> +$(filter dsdt_%.c,$(C_SRC)): %.c: %.asl iasl
> +	cpp -P $< > $<.i.orig
> +	$(PYTHON) ../tools/acpi_extract_preprocess.py $<.i.orig > $<.i
> +	iasl -vs -l -tc -p $* $<.i
> +	$(PYTHON) ../tools/acpi_extract.py $*.lst > $@.tmp
> +	echo "int $*_len=sizeof($*);" >> $@.tmp
> +	if grep -q "$*_aml_ej0_name" $@.tmp; then echo "int $*_aml_ej0_name_len=sizeof($*_aml_ej0_name);" >> $@.tmp; fi
> +	if grep -q "$*_aml_adr_dword" $@.tmp; then echo "int $*_aml_adr_dword_len=sizeof($*_aml_adr_dword);" >> $@.tmp; fi
> +	$(call move-if-changed,$@.tmp $@)
> +	rm -f $*.aml $*.hex $*.asl.i.orig $*.asl.i $*.lst
>   
>   iasl:
>   	@echo
> @@ -64,7 +79,7 @@ acpi.a: $(OBJS)
>   
>   clean:
>   	rm -rf *.a *.o $(IASL_VER) $(IASL_VER).tar.gz $(DEPS)
> -	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl
> +	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl *.asl.i *.asl.i.orig *.lst *.tmp
>   
>   install: all
>   
> diff --git a/tools/firmware/hvmloader/acpi/acpi2_0.h b/tools/firmware/hvmloader/acpi/acpi2_0.h
> index 7b22d80..4ba3957 100644
> --- a/tools/firmware/hvmloader/acpi/acpi2_0.h
> +++ b/tools/firmware/hvmloader/acpi/acpi2_0.h
> @@ -396,6 +396,10 @@ struct acpi_config {
>       int dsdt_anycpu_len;
>       unsigned char *dsdt_15cpu;
>       int dsdt_15cpu_len;
> +    unsigned short *aml_ej0_name;
> +    unsigned short *aml_adr_dword;
> +    int aml_ej0_name_len;
> +    int aml_adr_dword_len;
>   };
>   
>   void acpi_build_tables(struct acpi_config *config, unsigned int physical);
> diff --git a/tools/firmware/hvmloader/acpi/build.c b/tools/firmware/hvmloader/acpi/build.c
> index f1dd3f0..7eb21d3 100644
> --- a/tools/firmware/hvmloader/acpi/build.c
> +++ b/tools/firmware/hvmloader/acpi/build.c
> @@ -29,6 +29,7 @@
>   
>   #define align16(sz)        (((sz) + 15) & ~15)
>   #define fixed_strcpy(d, s) strncpy((d), (s), sizeof(d))
> +#define PCI_RMV_BASE 0xae0c
>   
>   extern struct acpi_20_rsdp Rsdp;
>   extern struct acpi_20_rsdt Rsdt;
> @@ -404,6 +405,7 @@ void acpi_build_tables(struct acpi_config *config, unsigned int physical)
>       unsigned char       *dsdt;
>       unsigned long        secondary_tables[ACPI_MAX_SECONDARY_TABLES];
>       int                  nr_secondaries, i;
> +    unsigned int rmvc_pcrm = 0;
>   
>       /* Allocate and initialise the acpi info area. */
>       mem_hole_populate_ram(ACPI_INFO_PHYSICAL_ADDRESS >> PAGE_SHIFT, 1);
> @@ -440,7 +442,24 @@ void acpi_build_tables(struct acpi_config *config, unsigned int physical)
>           memcpy(dsdt, config->dsdt_anycpu, config->dsdt_anycpu_len);
>           nr_processor_objects = HVM_MAX_VCPUS;
>       }
> -
> +    if(config->aml_adr_dword_len && config->aml_ej0_name_len &&
> +        (config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]) == config->aml_ej0_name_len/sizeof(config->aml_ej0_name[0])))
> +    {
> +        rmvc_pcrm = inl(PCI_RMV_BASE);
> +        for(i = 0;  i < config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]); i ++)
> +        {
> +            /* Slot is in byte 2 in _ADR */
> +            unsigned char slot = dsdt[config->aml_adr_dword[i] + 2] & 0x1F;
> +            /* Sanity check */
> +            if (memcmp(dsdt + config->aml_ej0_name[i], "_EJ0", 4)) {
> +                printf("Method '_EJ0' can not be found for pci slot %d\n", slot);
> +                return;
> +            }
> +            if (!(rmvc_pcrm & (0x1 << slot))) {
> +                memcpy(dsdt + config->aml_ej0_name[i], "EJ0_", 4);
> +            }
> +        }
> +    }
>       /*
>        * N.B. ACPI 1.0 operating systems may not handle FADT with revision 2
>        * or above properly, notably Windows 2000, which tries to copy FADT
> diff --git a/tools/firmware/hvmloader/acpi/dsdt.asl b/tools/firmware/hvmloader/acpi/dsdt.asl
> index 247a8ad..1e7695b 100644
> --- a/tools/firmware/hvmloader/acpi/dsdt.asl
> +++ b/tools/firmware/hvmloader/acpi/dsdt.asl
> @@ -16,6 +16,7 @@
>    * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
>    * Place - Suite 330, Boston, MA 02111-1307 USA.
>    */
> +ACPI_EXTRACT_ALL_CODE AmlCode
>   
>   DefinitionBlock ("DSDT.aml", "DSDT", 2, "Xen", "HVM", 0)
>   {
> diff --git a/tools/firmware/hvmloader/acpi/mk_dsdt.c b/tools/firmware/hvmloader/acpi/mk_dsdt.c
> index 996f30b..4180801 100644
> --- a/tools/firmware/hvmloader/acpi/mk_dsdt.c
> +++ b/tools/firmware/hvmloader/acpi/mk_dsdt.c
> @@ -368,7 +368,9 @@ int main(int argc, char **argv)
>           /* hotplug_slot */
>           for (slot = 1; slot <= 31; slot++) {
>               push_block("Device", "S%i", slot); {
> +                printf("ACPI_EXTRACT_NAME_DWORD_CONST aml_adr_dword\n");
>                   stmt("Name", "_ADR, %#06x0000", slot);
> +                printf("ACPI_EXTRACT_METHOD_STRING aml_ej0_name\n");
>                   push_block("Method", "_EJ0,1"); {
>                       stmt("Store", "ShiftLeft(1, %#06x), B0EJ", slot);
>                       stmt("Return", "0x0");
> diff --git a/tools/firmware/hvmloader/ovmf.c b/tools/firmware/hvmloader/ovmf.c
> index ee4cbbf..27ff0b5 100644
> --- a/tools/firmware/hvmloader/ovmf.c
> +++ b/tools/firmware/hvmloader/ovmf.c
> @@ -79,7 +79,11 @@ static void ovmf_acpi_build_tables(void)
>           .dsdt_anycpu = dsdt_anycpu,
>           .dsdt_anycpu_len = dsdt_anycpu_len,
>           .dsdt_15cpu = NULL,
> -        .dsdt_15cpu_len = 0
> +        .dsdt_15cpu_len = 0,
> +        .aml_ej0_name = NULL,
> +        .aml_adr_dword = NULL,
> +        .aml_ej0_name_len = 0,
> +        .aml_adr_dword_len = 0,
>       };
>   
>       acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
> diff --git a/tools/firmware/hvmloader/rombios.c b/tools/firmware/hvmloader/rombios.c
> index 810bd24..803c9fa 100644
> --- a/tools/firmware/hvmloader/rombios.c
> +++ b/tools/firmware/hvmloader/rombios.c
> @@ -179,6 +179,10 @@ static void rombios_acpi_build_tables(void)
>           .dsdt_anycpu_len = dsdt_anycpu_len,
>           .dsdt_15cpu = dsdt_15cpu,
>           .dsdt_15cpu_len = dsdt_15cpu_len,
> +        .aml_ej0_name = NULL,
> +        .aml_adr_dword = NULL,
> +        .aml_ej0_name_len = 0,
> +        .aml_adr_dword_len = 0,
>       };
>   
>       acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
> diff --git a/tools/firmware/hvmloader/seabios.c b/tools/firmware/hvmloader/seabios.c
> index dd7dfbe..ca01d27 100644
> --- a/tools/firmware/hvmloader/seabios.c
> +++ b/tools/firmware/hvmloader/seabios.c
> @@ -33,6 +33,10 @@
>   
>   extern unsigned char dsdt_anycpu_qemu_xen[];
>   extern int dsdt_anycpu_qemu_xen_len;
> +extern unsigned short dsdt_anycpu_qemu_xen_aml_ej0_name[];
> +extern unsigned short dsdt_anycpu_qemu_xen_aml_adr_dword[];
> +extern int dsdt_anycpu_qemu_xen_aml_ej0_name_len;
> +extern int dsdt_anycpu_qemu_xen_aml_adr_dword_len;
>   
>   struct seabios_info {
>       char signature[14]; /* XenHVMSeaBIOS\0 */
> @@ -99,6 +103,10 @@ static void seabios_acpi_build_tables(void)
>           .dsdt_anycpu_len = dsdt_anycpu_qemu_xen_len,
>           .dsdt_15cpu = NULL,
>           .dsdt_15cpu_len = 0,
> +        .aml_ej0_name = dsdt_anycpu_qemu_xen_aml_ej0_name,
> +        .aml_adr_dword = dsdt_anycpu_qemu_xen_aml_adr_dword,
> +        .aml_ej0_name_len = dsdt_anycpu_qemu_xen_aml_ej0_name_len,
> +        .aml_adr_dword_len = dsdt_anycpu_qemu_xen_aml_adr_dword_len,
>       };
>   
>       acpi_build_tables(&config, rsdp);
> diff --git a/tools/firmware/hvmloader/tools/acpi_extract.py b/tools/firmware/hvmloader/tools/acpi_extract.py
> new file mode 100644
> index 0000000..4fa51f7
> --- /dev/null
> +++ b/tools/firmware/hvmloader/tools/acpi_extract.py
> @@ -0,0 +1,308 @@
> +#!/usr/bin/python
> +# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
> +#
> +# This file may be distributed under the terms of the GNU GPLv3 license.
> +
> +# Process mixed ASL/AML listing (.lst file) produced by iasl -l
> +# Locate and execute ACPI_EXTRACT directives, output offset info
> +#
> +# Documentation of ACPI_EXTRACT_* directive tags:
> +#
> +# These directive tags output offset information from AML for BIOS runtime
> +# table generation.
> +# Each directive is of the form:
> +# ACPI_EXTRACT_<TYPE> <array_name> <Operator> (...)
> +# and causes the extractor to create an array
> +# named <array_name> with offset, in the generated AML,
> +# of an object of a given type in the following <Operator>.
> +#
> +# A directive must fit on a single code line.
> +#
> +# Object type in AML is verified, a mismatch causes a build failure.
> +#
> +# Directives and operators currently supported are:
> +# ACPI_EXTRACT_NAME_DWORD_CONST - extract a Dword Const object from Name()
> +# ACPI_EXTRACT_NAME_WORD_CONST - extract a Word Const object from Name()
> +# ACPI_EXTRACT_NAME_BYTE_CONST - extract a Byte Const object from Name()
> +# ACPI_EXTRACT_METHOD_STRING - extract a NameString from Method()
> +# ACPI_EXTRACT_NAME_STRING - extract a NameString from Name()
> +# ACPI_EXTRACT_PROCESSOR_START - start of Processor() block
> +# ACPI_EXTRACT_PROCESSOR_STRING - extract a NameString from Processor()
> +# ACPI_EXTRACT_PROCESSOR_END - offset at last byte of Processor() + 1
> +# ACPI_EXTRACT_PKG_START - start of Package block
> +#
> +# ACPI_EXTRACT_ALL_CODE - create an array storing the generated AML bytecode
> +#
> +# ACPI_EXTRACT is not allowed anywhere else in code, except in comments.
> +
> +import re;
> +import sys;
> +import fileinput;
> +
> +aml = []
> +asl = []
> +output = {}
> +debug = ""
> +
> +class asl_line:
> +    line = None
> +    lineno = None
> +    aml_offset = None
> +
> +def die(diag):
> +    sys.stderr.write("Error: %s; %s\n" % (diag, debug))
> +    sys.exit(1)
> +
> +#Store an ASL command, matching AML offset, and input line (for debugging)
> +def add_asl(lineno, line):
> +    l = asl_line()
> +    l.line = line
> +    l.lineno = lineno
> +    l.aml_offset = len(aml)
> +    asl.append(l)
> +
> +#Store an AML byte sequence
> +#Verify that offset output by iasl matches # of bytes so far
> +def add_aml(offset, line):
> +    o = int(offset, 16);
> +    # Sanity check: offset must match size of code so far
> +    if (o != len(aml)):
> +        die("Offset 0x%x != 0x%x" % (o, len(aml)))
> +    # Strip any trailing dots and ASCII dump after "
> +    line = re.sub(r'\s*\.*\s*".*$',"", line)
> +    # Strip traling whitespace
> +    line = re.sub(r'\s+$',"", line)
> +    # Strip leading whitespace
> +    line = re.sub(r'^\s+',"", line)
> +    # Split on whitespace
> +    code = re.split(r'\s+', line)
> +    for c in code:
> +        # Require a legal hex number, two digits
> +        if (not(re.search(r'^[0-9A-Fa-f][0-9A-Fa-f]$', c))):
> +            die("Unexpected octet %s" % c);
> +        aml.append(int(c, 16));
> +
> +# Process aml bytecode array, decoding AML
> +def aml_pkglen_bytes(offset):
> +    # PkgLength can be multibyte. Bits 8-7 give the # of extra bytes.
> +    pkglenbytes = aml[offset] >> 6;
> +    return pkglenbytes + 1
> +
> +def aml_pkglen(offset):
> +    pkgstart = offset
> +    pkglenbytes = aml_pkglen_bytes(offset)
> +    pkglen = aml[offset] & 0x3F
> +    # If multibyte, first nibble only uses bits 0-3
> +    if ((pkglenbytes > 0) and (pkglen & 0x30)):
> +        die("PkgLen bytes 0x%x but first nibble 0x%x expected 0x0X" %
> +            (pkglen, pkglen))
> +    offset += 1
> +    pkglenbytes -= 1
> +    for i in range(pkglenbytes):
> +        pkglen |= aml[offset + i] << (i * 8 + 4)
> +    if (len(aml) < pkgstart + pkglen):
> +        die("PckgLen 0x%x at offset 0x%x exceeds AML size 0x%x" %
> +            (pkglen, offset, len(aml)))
> +    return pkglen
> +
> +# Given method offset, find its NameString offset
> +def aml_method_string(offset):
> +    #0x14 MethodOp PkgLength NameString MethodFlags TermList
> +    if (aml[offset] != 0x14):
> +        die( "Method offset 0x%x: expected 0x14 actual 0x%x" %
> +             (offset, aml[offset]));
> +    offset += 1;
> +    pkglenbytes = aml_pkglen_bytes(offset)
> +    offset += pkglenbytes;
> +    return offset;
> +
> +# Given name offset, find its NameString offset
> +def aml_name_string(offset):
> +    #0x08 NameOp NameString DataRef
> +    if (aml[offset] != 0x08):
> +        die( "Name offset 0x%x: expected 0x08 actual 0x%x" %
> +             (offset, aml[offset]));
> +    offset += 1
> +    # Block Name Modifier. Skip it.
> +    if (aml[offset] == 0x5c or aml[offset] == 0x5e):
> +        offset += 1
> +    return offset;
> +
> +# Given data offset, find dword const offset
> +def aml_data_dword_const(offset):
> +    #0x08 NameOp NameString DataRef
> +    if (aml[offset] != 0x0C):
> +        die( "Name offset 0x%x: expected 0x0C actual 0x%x" %
> +             (offset, aml[offset]));
> +    return offset + 1;
> +
> +# Given data offset, find word const offset
> +def aml_data_word_const(offset):
> +    #0x08 NameOp NameString DataRef
> +    if (aml[offset] != 0x0B):
> +        die( "Name offset 0x%x: expected 0x0B actual 0x%x" %
> +             (offset, aml[offset]));
> +    return offset + 1;
> +
> +# Given data offset, find byte const offset
> +def aml_data_byte_const(offset):
> +    #0x08 NameOp NameString DataRef
> +    if (aml[offset] != 0x0A):
> +        die( "Name offset 0x%x: expected 0x0A actual 0x%x" %
> +             (offset, aml[offset]));
> +    return offset + 1;
> +
> +# Given name offset, find dword const offset
> +def aml_name_dword_const(offset):
> +    return aml_data_dword_const(aml_name_string(offset) + 4)
> +
> +# Given name offset, find word const offset
> +def aml_name_word_const(offset):
> +    return aml_data_word_const(aml_name_string(offset) + 4)
> +
> +# Given name offset, find byte const offset
> +def aml_name_byte_const(offset):
> +    return aml_data_byte_const(aml_name_string(offset) + 4)
> +
> +def aml_processor_start(offset):
> +    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
> +    if ((aml[offset] != 0x5B) or (aml[offset + 1] != 0x83)):
> +        die( "Name offset 0x%x: expected 0x5B 0x83 actual 0x%x 0x%x" %
> +             (offset, aml[offset], aml[offset + 1]));
> +    return offset
> +
> +def aml_processor_string(offset):
> +    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
> +    start = aml_processor_start(offset)
> +    offset += 2
> +    pkglenbytes = aml_pkglen_bytes(offset)
> +    offset += pkglenbytes
> +    return offset
> +
> +def aml_processor_end(offset):
> +    start = aml_processor_start(offset)
> +    offset += 2
> +    pkglenbytes = aml_pkglen_bytes(offset)
> +    pkglen = aml_pkglen(offset)
> +    return offset + pkglen
> +
> +def aml_package_start(offset):
> +    offset = aml_name_string(offset) + 4
> +    # 0x12 PkgLength NumElements PackageElementList
> +    if (aml[offset] != 0x12):
> +        die( "Name offset 0x%x: expected 0x12 actual 0x%x" %
> +             (offset, aml[offset]));
> +    offset += 1
> +    return offset + aml_pkglen_bytes(offset) + 1
> +
> +lineno = 0
> +for line in fileinput.input():
> +    # Strip trailing newline
> +    line = line.rstrip();
> +    # line number and debug string to output in case of errors
> +    lineno = lineno + 1
> +    debug = "input line %d: %s" % (lineno, line)
> +    #ASL listing: space, then line#, then ...., then code
> +    pasl = re.compile('^\s+([0-9]+)\.\.\.\.\s*')
> +    m = pasl.search(line)
> +    if (m):
> +        add_asl(lineno, pasl.sub("", line));
> +    # AML listing: offset in hex, then ...., then code
> +    paml = re.compile('^([0-9A-Fa-f]+)\.\.\.\.\s*')
> +    m = paml.search(line)
> +    if (m):
> +        add_aml(m.group(1), paml.sub("", line))
> +
> +# Now go over code
> +# Track AML offset of a previous non-empty ASL command
> +prev_aml_offset = -1
> +for i in range(len(asl)):
> +    debug = "input line %d: %s" % (asl[i].lineno, asl[i].line)
> +
> +    l = asl[i].line
> +
> +    # skip if not an extract directive
> +    a = len(re.findall(r'ACPI_EXTRACT', l))
> +    if (not a):
> +        # If not empty, store AML offset. Will be used for sanity checks
> +        # IASL seems to put {}. at random places in the listing.
> +        # Ignore any non-words for the purpose of this test.
> +        m = re.search(r'\w+', l)
> +        if (m):
> +                prev_aml_offset = asl[i].aml_offset
> +        continue
> +
> +    if (a > 1):
> +        die("Expected at most one ACPI_EXTRACT per line, actual %d" % a)
> +
> +    mext = re.search(r'''
> +                      ^\s* # leading whitespace
> +                      /\*\s* # start C comment
> +                      (ACPI_EXTRACT_\w+) # directive: group(1)
> +                      \s+ # whitspace separates directive from array name
> +                      (\w+) # array name: group(2)
> +                      \s*\*/ # end of C comment
> +                      \s*$ # trailing whitespace
> +                      ''', l, re.VERBOSE)
> +    if (not mext):
> +        die("Stray ACPI_EXTRACT in input")
> +
> +    # previous command must have produced some AML,
> +    # otherwise we are in a middle of a block
> +    if (prev_aml_offset == asl[i].aml_offset):
> +        die("ACPI_EXTRACT directive in the middle of a block")
> +
> +    directive = mext.group(1)
> +    array = mext.group(2)
> +    offset = asl[i].aml_offset
> +
> +    if (directive == "ACPI_EXTRACT_ALL_CODE"):
> +        if array in output:
> +            die("%s directive used more than once" % directive)
> +        output[array] = aml
> +        continue
> +    if (directive == "ACPI_EXTRACT_NAME_DWORD_CONST"):
> +        offset = aml_name_dword_const(offset)
> +    elif (directive == "ACPI_EXTRACT_NAME_WORD_CONST"):
> +        offset = aml_name_word_const(offset)
> +    elif (directive == "ACPI_EXTRACT_NAME_BYTE_CONST"):
> +        offset = aml_name_byte_const(offset)
> +    elif (directive == "ACPI_EXTRACT_NAME_STRING"):
> +        offset = aml_name_string(offset)
> +    elif (directive == "ACPI_EXTRACT_METHOD_STRING"):
> +        offset = aml_method_string(offset)
> +    elif (directive == "ACPI_EXTRACT_PROCESSOR_START"):
> +        offset = aml_processor_start(offset)
> +    elif (directive == "ACPI_EXTRACT_PROCESSOR_STRING"):
> +        offset = aml_processor_string(offset)
> +    elif (directive == "ACPI_EXTRACT_PROCESSOR_END"):
> +        offset = aml_processor_end(offset)
> +    elif (directive == "ACPI_EXTRACT_PKG_START"):
> +        offset = aml_package_start(offset)
> +    else:
> +        die("Unsupported directive %s" % directive)
> +
> +    if array not in output:
> +        output[array] = []
> +    output[array].append(offset)
> +
> +debug = "at end of file"
> +
> +def get_value_type(maxvalue):
> +    #Use type large enough to fit the table
> +    if (maxvalue >= 0x10000):
> +            return "int"
> +    elif (maxvalue >= 0x100):
> +            return "short"
> +    else:
> +            return "char"
> +
> +# Pretty print output
> +for array in output.keys():
> +    otype = get_value_type(max(output[array]))
> +    odata = []
> +    for value in output[array]:
> +        odata.append("0x%x" % value)
> +    sys.stdout.write("unsigned %s %s[] = {\n" % (otype, array))
> +    sys.stdout.write(",\n".join(odata))
> +    sys.stdout.write('\n};\n');
> diff --git a/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py b/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py
> new file mode 100644
> index 0000000..4ae364e
> --- /dev/null
> +++ b/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py
> @@ -0,0 +1,41 @@
> +#!/usr/bin/python
> +# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
> +#
> +# This file may be distributed under the terms of the GNU GPLv3 license.
> +
> +# Read a preprocessed ASL listing and put each ACPI_EXTRACT
> +# directive in a comment, to make iasl skip it.
> +# We also put each directive on a new line, the machinery
> +# in tools/acpi_extract.py requires this.
> +
> +import re;
> +import sys;
> +import fileinput;
> +
> +def die(diag):
> +    sys.stderr.write("Error: %s\n" % (diag))
> +    sys.exit(1)
> +
> +# Note: () around pattern make split return matched string as part of list
> +psplit = re.compile(r''' (
> +                          \b # At word boundary
> +                          ACPI_EXTRACT_\w+ # directive
> +                          \s+ # some whitespace
> +                          \w+ # array name
> +                         )''', re.VERBOSE);
> +
> +lineno = 0
> +for line in fileinput.input():
> +    # line number and debug string to output in case of errors
> +    lineno = lineno + 1
> +    debug = "input line %d: %s" % (lineno, line.rstrip())
> +
> +    s = psplit.split(line);
> +    # The way split works, each odd item is the matching ACPI_EXTRACT directive.
> +    # Put each in a comment, and on a line by itself.
> +    for i in range(len(s)):
> +        if (i % 2):
> +            sys.stdout.write("\n/* %s */\n" % s[i])
> +        else:
> +            sys.stdout.write(s[i])
> +

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [Xen-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
  2013-10-24 12:57                   ` Fabio Fantoni
  2013-10-24 13:16                     ` [Qemu-devel] " Gonglei (Arei)
@ 2013-10-24 13:16                     ` Gonglei (Arei)
  1 sibling, 0 replies; 38+ messages in thread
From: Gonglei (Arei) @ 2013-10-24 13:16 UTC (permalink / raw)
  To: Fabio Fantoni, Jan Beulich
  Cc: Yanqiangjun, Ian Campbell, Hanweidong (Randy),
	Markus Armbruster, Stefano Stabellini, Luonengjun, qemu-devel,
	xen-devel, anthony.perard, Gaowei (UVP), Huangweidong (Hardware)

> -----Original Message-----
> From: Fabio Fantoni [mailto:fabio.fantoni@m2r.biz]
> Sent: Thursday, October 24, 2013 8:58 PM
> To: Gonglei (Arei); Jan Beulich
> Cc: anthony.perard@citrix.com; Ian Campbell; Stefano Stabellini; Gaowei (UVP);
> Hanweidong (Randy); Huangweidong (Hardware); Luonengjun; Yanqiangjun;
> xen-devel@lists.xen.org; qemu-devel@nongnu.org; Markus Armbruster
> Subject: Re: [Qemu-devel] [Xen-devel] Hvmloader: Modify ACPI to only supply
> _EJ0 methods for PCIslots that support hotplug by runtime patching
> 
> Il 24/10/2013 14:17, Gonglei (Arei) ha scritto:
> >> -----Original Message-----
> >> From: Jan Beulich [mailto:JBeulich@suse.com]
> >> Sent: Tuesday, October 22, 2013 4:06 PM
> >> To: Gonglei (Arei)
> >> Cc: anthony.perard@citrix.com; Ian Campbell; Stefano Stabellini; Gaowei
> (UVP);
> >> Hanweidong (Randy); Huangweidong (Hardware); Luonengjun; Yanqiangjun;
> >> xen-devel@lists.xen.org; Fabio Fantoni; qemu-devel@nongnu.org; Markus
> >> Armbruster
> >> Subject: RE: [Qemu-devel] [Xen-devel] Hvmloader: Modify ACPI to only
> supply
> >> _EJ0 methods for PCIslots that support hotplug by runtime patching
> >>
> >>>>> On 22.10.13 at 06:08, "Gonglei (Arei)" <arei.gonglei@huawei.com>
> wrote:
> >>> Hi, guys. The new patch has been modified based on the principles you
> >>> suggested, thank you so much.
> >>> Last time I test the patch based on the codes of 4.3.0.
> >>> This time, I found that the system based on the codes of trunk causes the
> VM
> >>> reboot again and again, which I have not found out the reason.
> >>> So i can not test the patch based on the codes of trunk (details in
> >>> EJ0_ACPI_PCI_Hotplug.patch)..
> >> I'm afraid we will need you to figure out that problem first, and
> >> then do the verification on -unstable. Even if the code shouldn't
> >> be that different from 4.3, we still don't want to apply completely
> >> untested stuff.
> > Hi, Jan. We found that the reason that we used a wrong seabios PATH, and
> the hvmloader can't load the bios.bin.
> > So the VM restart again and again after we start it. That's our fault.
> >
> > Now I test the patch based on the codes of trunk, which works well.
> > The patch has been modified after your suggestion.
> > The patch works well with upstream qemu and doesn't affect the system with
> traditional qemu.
> >
> >>
> >>> --- a/tools/firmware/hvmloader/ovmf.c
> >>> +++ b/tools/firmware/hvmloader/ovmf.c
> >>> @@ -79,7 +79,11 @@ static void ovmf_acpi_build_tables(void)
> >>>           .dsdt_anycpu = dsdt_anycpu,
> >>>           .dsdt_anycpu_len = dsdt_anycpu_len,
> >>>           .dsdt_15cpu = NULL,
> >>> -        .dsdt_15cpu_len = 0
> >>> +        .dsdt_15cpu_len = 0,
> >>> +        .aml_ej0_name = NULL,
> >>> +        .aml_adr_dword = NULL,
> >>> +        .aml_ej0_name_len = 0,
> >>> +        .aml_adr_dword_len = 0,
> >> I don't see why you're adding these.
> >>
> > Insurance purposes is that just initialize the struct.
> >
> > Signed-off-by: Gaowei <gao.gaowei@huawei.com>
> > Signed-off-by: gonglei <arei.gonglei@huawei.com>
> 
> Tested-by: Fabio Fantoni <fabio.fantoni@m2r.biz>
> 
> Tested on xen unstable with qemu 1.6.1, no problem found for now.
> Only one question: this patch remove hotplug only from essentials pci
> device, right?
> On windows 7 hotplug continues to show: virtio-serial driver, xen pci
> device driver and hd audio.
> 
It depends on the property of hotplug of pci devices' class emulated by upstream qemu.
If you set k->no_hotplug = 1 in class_init function for those pci devices, 
which will not be shown in the Windows guest any more.

> Thanks for any reply.
> 

Best regards,
-Gonglei

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
  2013-10-24 12:57                   ` Fabio Fantoni
@ 2013-10-24 13:16                     ` Gonglei (Arei)
  2013-10-24 13:16                     ` [Qemu-devel] [Xen-devel] " Gonglei (Arei)
  1 sibling, 0 replies; 38+ messages in thread
From: Gonglei (Arei) @ 2013-10-24 13:16 UTC (permalink / raw)
  To: Fabio Fantoni, Jan Beulich
  Cc: Yanqiangjun, Ian Campbell, Hanweidong (Randy),
	Markus Armbruster, Stefano Stabellini, Luonengjun, qemu-devel,
	xen-devel, anthony.perard, Gaowei (UVP), Huangweidong (Hardware)

> -----Original Message-----
> From: Fabio Fantoni [mailto:fabio.fantoni@m2r.biz]
> Sent: Thursday, October 24, 2013 8:58 PM
> To: Gonglei (Arei); Jan Beulich
> Cc: anthony.perard@citrix.com; Ian Campbell; Stefano Stabellini; Gaowei (UVP);
> Hanweidong (Randy); Huangweidong (Hardware); Luonengjun; Yanqiangjun;
> xen-devel@lists.xen.org; qemu-devel@nongnu.org; Markus Armbruster
> Subject: Re: [Qemu-devel] [Xen-devel] Hvmloader: Modify ACPI to only supply
> _EJ0 methods for PCIslots that support hotplug by runtime patching
> 
> Il 24/10/2013 14:17, Gonglei (Arei) ha scritto:
> >> -----Original Message-----
> >> From: Jan Beulich [mailto:JBeulich@suse.com]
> >> Sent: Tuesday, October 22, 2013 4:06 PM
> >> To: Gonglei (Arei)
> >> Cc: anthony.perard@citrix.com; Ian Campbell; Stefano Stabellini; Gaowei
> (UVP);
> >> Hanweidong (Randy); Huangweidong (Hardware); Luonengjun; Yanqiangjun;
> >> xen-devel@lists.xen.org; Fabio Fantoni; qemu-devel@nongnu.org; Markus
> >> Armbruster
> >> Subject: RE: [Qemu-devel] [Xen-devel] Hvmloader: Modify ACPI to only
> supply
> >> _EJ0 methods for PCIslots that support hotplug by runtime patching
> >>
> >>>>> On 22.10.13 at 06:08, "Gonglei (Arei)" <arei.gonglei@huawei.com>
> wrote:
> >>> Hi, guys. The new patch has been modified based on the principles you
> >>> suggested, thank you so much.
> >>> Last time I test the patch based on the codes of 4.3.0.
> >>> This time, I found that the system based on the codes of trunk causes the
> VM
> >>> reboot again and again, which I have not found out the reason.
> >>> So i can not test the patch based on the codes of trunk (details in
> >>> EJ0_ACPI_PCI_Hotplug.patch)..
> >> I'm afraid we will need you to figure out that problem first, and
> >> then do the verification on -unstable. Even if the code shouldn't
> >> be that different from 4.3, we still don't want to apply completely
> >> untested stuff.
> > Hi, Jan. We found that the reason that we used a wrong seabios PATH, and
> the hvmloader can't load the bios.bin.
> > So the VM restart again and again after we start it. That's our fault.
> >
> > Now I test the patch based on the codes of trunk, which works well.
> > The patch has been modified after your suggestion.
> > The patch works well with upstream qemu and doesn't affect the system with
> traditional qemu.
> >
> >>
> >>> --- a/tools/firmware/hvmloader/ovmf.c
> >>> +++ b/tools/firmware/hvmloader/ovmf.c
> >>> @@ -79,7 +79,11 @@ static void ovmf_acpi_build_tables(void)
> >>>           .dsdt_anycpu = dsdt_anycpu,
> >>>           .dsdt_anycpu_len = dsdt_anycpu_len,
> >>>           .dsdt_15cpu = NULL,
> >>> -        .dsdt_15cpu_len = 0
> >>> +        .dsdt_15cpu_len = 0,
> >>> +        .aml_ej0_name = NULL,
> >>> +        .aml_adr_dword = NULL,
> >>> +        .aml_ej0_name_len = 0,
> >>> +        .aml_adr_dword_len = 0,
> >> I don't see why you're adding these.
> >>
> > Insurance purposes is that just initialize the struct.
> >
> > Signed-off-by: Gaowei <gao.gaowei@huawei.com>
> > Signed-off-by: gonglei <arei.gonglei@huawei.com>
> 
> Tested-by: Fabio Fantoni <fabio.fantoni@m2r.biz>
> 
> Tested on xen unstable with qemu 1.6.1, no problem found for now.
> Only one question: this patch remove hotplug only from essentials pci
> device, right?
> On windows 7 hotplug continues to show: virtio-serial driver, xen pci
> device driver and hd audio.
> 
It depends on the property of hotplug of pci devices' class emulated by upstream qemu.
If you set k->no_hotplug = 1 in class_init function for those pci devices, 
which will not be shown in the Windows guest any more.

> Thanks for any reply.
> 

Best regards,
-Gonglei

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [Xen-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
  2013-10-22  8:06               ` [Qemu-devel] [Xen-devel] " Jan Beulich
                                   ` (2 preceding siblings ...)
  2013-10-28  7:14                 ` Gonglei (Arei)
@ 2013-10-28  7:14                 ` Gonglei (Arei)
  3 siblings, 0 replies; 38+ messages in thread
From: Gonglei (Arei) @ 2013-10-28  7:14 UTC (permalink / raw)
  To: Gonglei (Arei), Jan Beulich
  Cc: Yanqiangjun, Ian Campbell, Hanweidong (Randy),
	Markus Armbruster, Stefano Stabellini, Luonengjun, qemu-devel,
	xen-devel, Fabio Fantoni, anthony.perard, Gaowei (UVP),
	Huangweidong (Hardware)

Hi,

Please post any comments or questions if you get around to testing them. 
Your comments are very welcome!

Best regards,
-Gonglei

> > >>> On 22.10.13 at 06:08, "Gonglei (Arei)" <arei.gonglei@huawei.com>
> wrote:
> > > Hi, guys. The new patch has been modified based on the principles you
> > > suggested, thank you so much.
> > > Last time I test the patch based on the codes of 4.3.0.
> > > This time, I found that the system based on the codes of trunk causes the
> VM
> > > reboot again and again, which I have not found out the reason.
> > > So i can not test the patch based on the codes of trunk (details in
> > > EJ0_ACPI_PCI_Hotplug.patch)..
> >
> > I'm afraid we will need you to figure out that problem first, and
> > then do the verification on -unstable. Even if the code shouldn't
> > be that different from 4.3, we still don't want to apply completely
> > untested stuff.
> 
> Hi, Jan. We found that the reason that we used a wrong seabios PATH, and the
> hvmloader can't load the bios.bin.
> So the VM restart again and again after we start it. That's our fault.
> 
> Now I test the patch based on the codes of trunk, which works well.
> The patch has been modified after your suggestion.
> The patch works well with upstream qemu and doesn't affect the system with
> traditional qemu.
> 
> >
> >
> > > --- a/tools/firmware/hvmloader/ovmf.c
> > > +++ b/tools/firmware/hvmloader/ovmf.c
> > > @@ -79,7 +79,11 @@ static void ovmf_acpi_build_tables(void)
> > >          .dsdt_anycpu = dsdt_anycpu,
> > >          .dsdt_anycpu_len = dsdt_anycpu_len,
> > >          .dsdt_15cpu = NULL,
> > > -        .dsdt_15cpu_len = 0
> > > +        .dsdt_15cpu_len = 0,
> > > +        .aml_ej0_name = NULL,
> > > +        .aml_adr_dword = NULL,
> > > +        .aml_ej0_name_len = 0,
> > > +        .aml_adr_dword_len = 0,
> >
> > I don't see why you're adding these.
> >
> Insurance purposes is that just initialize the struct.
> 
> Signed-off-by: Gaowei <gao.gaowei@huawei.com>
> Signed-off-by: gonglei <arei.gonglei@huawei.com>
> ---
>  tools/firmware/hvmloader/acpi/Makefile             |  37 ++-
>  tools/firmware/hvmloader/acpi/acpi2_0.h            |   4 +
>  tools/firmware/hvmloader/acpi/build.c              |  21 +-
>  tools/firmware/hvmloader/acpi/dsdt.asl             |   1 +
>  tools/firmware/hvmloader/acpi/mk_dsdt.c            |   2 +
>  tools/firmware/hvmloader/ovmf.c                    |   6 +-
>  tools/firmware/hvmloader/rombios.c                 |   4 +
>  tools/firmware/hvmloader/seabios.c                 |   8 +
>  tools/firmware/hvmloader/tools/acpi_extract.py     | 308
> +++++++++++++++++++++
>  .../hvmloader/tools/acpi_extract_preprocess.py     |  41 +++
>  10 files changed, 419 insertions(+), 13 deletions(-)
>  create mode 100644 tools/firmware/hvmloader/tools/acpi_extract.py
>  create mode 100644
> tools/firmware/hvmloader/tools/acpi_extract_preprocess.py
> 
> diff --git a/tools/firmware/hvmloader/acpi/Makefile
> b/tools/firmware/hvmloader/acpi/Makefile
> index 2c50851..b96e058 100644
> --- a/tools/firmware/hvmloader/acpi/Makefile
> +++ b/tools/firmware/hvmloader/acpi/Makefile
> @@ -24,30 +24,45 @@ OBJS  = $(patsubst %.c,%.o,$(C_SRC))
>  CFLAGS += $(CFLAGS_xeninclude)
> 
>  vpath iasl $(PATH)
> +
> +.DELETE_ON_ERROR: $(filter dsdt_%.c,$(C_SRC))
> +
>  all: acpi.a
> 
>  ssdt_s3.h ssdt_s4.h ssdt_pm.h ssdt_tpm.h: %.h: %.asl iasl
>  	iasl -vs -p $* -tc $<
> -	sed -e 's/AmlCode/$*/g' $*.hex >$@
> +	sed -e 's/AmlCode/$*/g' $*.hex > $@.tmp
> +	$(call move-if-changed,$@.tmp $@)
>  	rm -f $*.hex $*.aml
> 
>  mk_dsdt: mk_dsdt.c
>  	$(HOSTCC) $(HOSTCFLAGS) $(CFLAGS_xeninclude) -o $@ mk_dsdt.c
> 
>  dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
> -	awk 'NR > 1 {print s} {s=$$0}' $< > $@
> -	./mk_dsdt --dm-version qemu-xen >> $@
> +	awk 'NR > 1 {print s} {s=$$0}' $< > $@.tmp
> +	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@.tmp
> +	./mk_dsdt --dm-version qemu-xen >> $@.tmp
> +	sed -i 's/aml_ej0_name/dsdt_anycpu_qemu_xen_aml_ej0_name/g'
> $@.tmp
> +	sed -i 's/aml_adr_dword/dsdt_anycpu_qemu_xen_aml_adr_dword/g'
> $@.tmp
> +	$(call move-if-changed,$@.tmp $@)
> 
>  # NB. awk invocation is a portable alternative to 'head -n -1'
>  dsdt_%cpu.asl: dsdt.asl mk_dsdt
> -	awk 'NR > 1 {print s} {s=$$0}' $< > $@
> -	./mk_dsdt --maxcpu $*  >> $@
> +	awk 'NR > 1 {print s} {s=$$0}' $< > $@.tmp
> +	sed -i 's/AmlCode/dsdt_$*cpu/g' $@.tmp
> +	./mk_dsdt --maxcpu $*  >> $@.tmp
> +	$(call move-if-changed,$@.tmp $@)
> 
> -$(filter dsdt_%.c,$(C_SRC)): %.c: iasl %.asl
> -	iasl -vs -p $* -tc $*.asl
> -	sed -e 's/AmlCode/$*/g' $*.hex >$@
> -	echo "int $*_len=sizeof($*);" >>$@
> -	rm -f $*.aml $*.hex
> +$(filter dsdt_%.c,$(C_SRC)): %.c: %.asl iasl
> +	cpp -P $< > $<.i.orig
> +	$(PYTHON) ../tools/acpi_extract_preprocess.py $<.i.orig > $<.i
> +	iasl -vs -l -tc -p $* $<.i
> +	$(PYTHON) ../tools/acpi_extract.py $*.lst > $@.tmp
> +	echo "int $*_len=sizeof($*);" >> $@.tmp
> +	if grep -q "$*_aml_ej0_name" $@.tmp; then echo "int
> $*_aml_ej0_name_len=sizeof($*_aml_ej0_name);" >> $@.tmp; fi
> +	if grep -q "$*_aml_adr_dword" $@.tmp; then echo "int
> $*_aml_adr_dword_len=sizeof($*_aml_adr_dword);" >> $@.tmp; fi
> +	$(call move-if-changed,$@.tmp $@)
> +	rm -f $*.aml $*.hex $*.asl.i.orig $*.asl.i $*.lst
> 
>  iasl:
>  	@echo
> @@ -64,7 +79,7 @@ acpi.a: $(OBJS)
> 
>  clean:
>  	rm -rf *.a *.o $(IASL_VER) $(IASL_VER).tar.gz $(DEPS)
> -	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl
> +	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl *.asl.i
> *.asl.i.orig *.lst *.tmp
> 
>  install: all
> 
> diff --git a/tools/firmware/hvmloader/acpi/acpi2_0.h
> b/tools/firmware/hvmloader/acpi/acpi2_0.h
> index 7b22d80..4ba3957 100644
> --- a/tools/firmware/hvmloader/acpi/acpi2_0.h
> +++ b/tools/firmware/hvmloader/acpi/acpi2_0.h
> @@ -396,6 +396,10 @@ struct acpi_config {
>      int dsdt_anycpu_len;
>      unsigned char *dsdt_15cpu;
>      int dsdt_15cpu_len;
> +    unsigned short *aml_ej0_name;
> +    unsigned short *aml_adr_dword;
> +    int aml_ej0_name_len;
> +    int aml_adr_dword_len;
>  };
> 
>  void acpi_build_tables(struct acpi_config *config, unsigned int physical);
> diff --git a/tools/firmware/hvmloader/acpi/build.c
> b/tools/firmware/hvmloader/acpi/build.c
> index f1dd3f0..7eb21d3 100644
> --- a/tools/firmware/hvmloader/acpi/build.c
> +++ b/tools/firmware/hvmloader/acpi/build.c
> @@ -29,6 +29,7 @@
> 
>  #define align16(sz)        (((sz) + 15) & ~15)
>  #define fixed_strcpy(d, s) strncpy((d), (s), sizeof(d))
> +#define PCI_RMV_BASE 0xae0c
> 
>  extern struct acpi_20_rsdp Rsdp;
>  extern struct acpi_20_rsdt Rsdt;
> @@ -404,6 +405,7 @@ void acpi_build_tables(struct acpi_config *config,
> unsigned int physical)
>      unsigned char       *dsdt;
>      unsigned long
> secondary_tables[ACPI_MAX_SECONDARY_TABLES];
>      int                  nr_secondaries, i;
> +    unsigned int rmvc_pcrm = 0;
> 
>      /* Allocate and initialise the acpi info area. */
>      mem_hole_populate_ram(ACPI_INFO_PHYSICAL_ADDRESS >>
> PAGE_SHIFT, 1);
> @@ -440,7 +442,24 @@ void acpi_build_tables(struct acpi_config *config,
> unsigned int physical)
>          memcpy(dsdt, config->dsdt_anycpu, config->dsdt_anycpu_len);
>          nr_processor_objects = HVM_MAX_VCPUS;
>      }
> -
> +    if(config->aml_adr_dword_len && config->aml_ej0_name_len &&
> +        (config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]) ==
> config->aml_ej0_name_len/sizeof(config->aml_ej0_name[0])))
> +    {
> +        rmvc_pcrm = inl(PCI_RMV_BASE);
> +        for(i = 0;  i <
> config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]); i ++)
> +        {
> +            /* Slot is in byte 2 in _ADR */
> +            unsigned char slot = dsdt[config->aml_adr_dword[i] + 2] &
> 0x1F;
> +            /* Sanity check */
> +            if (memcmp(dsdt + config->aml_ej0_name[i], "_EJ0", 4)) {
> +                printf("Method '_EJ0' can not be found for pci slot %d\n",
> slot);
> +                return;
> +            }
> +            if (!(rmvc_pcrm & (0x1 << slot))) {
> +                memcpy(dsdt + config->aml_ej0_name[i], "EJ0_", 4);
> +            }
> +        }
> +    }
>      /*
>       * N.B. ACPI 1.0 operating systems may not handle FADT with revision 2
>       * or above properly, notably Windows 2000, which tries to copy FADT
> diff --git a/tools/firmware/hvmloader/acpi/dsdt.asl
> b/tools/firmware/hvmloader/acpi/dsdt.asl
> index 247a8ad..1e7695b 100644
> --- a/tools/firmware/hvmloader/acpi/dsdt.asl
> +++ b/tools/firmware/hvmloader/acpi/dsdt.asl
> @@ -16,6 +16,7 @@
>   * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
>   * Place - Suite 330, Boston, MA 02111-1307 USA.
>   */
> +ACPI_EXTRACT_ALL_CODE AmlCode
> 
>  DefinitionBlock ("DSDT.aml", "DSDT", 2, "Xen", "HVM", 0)
>  {
> diff --git a/tools/firmware/hvmloader/acpi/mk_dsdt.c
> b/tools/firmware/hvmloader/acpi/mk_dsdt.c
> index 996f30b..4180801 100644
> --- a/tools/firmware/hvmloader/acpi/mk_dsdt.c
> +++ b/tools/firmware/hvmloader/acpi/mk_dsdt.c
> @@ -368,7 +368,9 @@ int main(int argc, char **argv)
>          /* hotplug_slot */
>          for (slot = 1; slot <= 31; slot++) {
>              push_block("Device", "S%i", slot); {
> +                printf("ACPI_EXTRACT_NAME_DWORD_CONST
> aml_adr_dword\n");
>                  stmt("Name", "_ADR, %#06x0000", slot);
> +                printf("ACPI_EXTRACT_METHOD_STRING
> aml_ej0_name\n");
>                  push_block("Method", "_EJ0,1"); {
>                      stmt("Store", "ShiftLeft(1, %#06x), B0EJ", slot);
>                      stmt("Return", "0x0");
> diff --git a/tools/firmware/hvmloader/ovmf.c
> b/tools/firmware/hvmloader/ovmf.c
> index ee4cbbf..27ff0b5 100644
> --- a/tools/firmware/hvmloader/ovmf.c
> +++ b/tools/firmware/hvmloader/ovmf.c
> @@ -79,7 +79,11 @@ static void ovmf_acpi_build_tables(void)
>          .dsdt_anycpu = dsdt_anycpu,
>          .dsdt_anycpu_len = dsdt_anycpu_len,
>          .dsdt_15cpu = NULL,
> -        .dsdt_15cpu_len = 0
> +        .dsdt_15cpu_len = 0,
> +        .aml_ej0_name = NULL,
> +        .aml_adr_dword = NULL,
> +        .aml_ej0_name_len = 0,
> +        .aml_adr_dword_len = 0,
>      };
> 
>      acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
> diff --git a/tools/firmware/hvmloader/rombios.c
> b/tools/firmware/hvmloader/rombios.c
> index 810bd24..803c9fa 100644
> --- a/tools/firmware/hvmloader/rombios.c
> +++ b/tools/firmware/hvmloader/rombios.c
> @@ -179,6 +179,10 @@ static void rombios_acpi_build_tables(void)
>          .dsdt_anycpu_len = dsdt_anycpu_len,
>          .dsdt_15cpu = dsdt_15cpu,
>          .dsdt_15cpu_len = dsdt_15cpu_len,
> +        .aml_ej0_name = NULL,
> +        .aml_adr_dword = NULL,
> +        .aml_ej0_name_len = 0,
> +        .aml_adr_dword_len = 0,
>      };
> 
>      acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
> diff --git a/tools/firmware/hvmloader/seabios.c
> b/tools/firmware/hvmloader/seabios.c
> index dd7dfbe..ca01d27 100644
> --- a/tools/firmware/hvmloader/seabios.c
> +++ b/tools/firmware/hvmloader/seabios.c
> @@ -33,6 +33,10 @@
> 
>  extern unsigned char dsdt_anycpu_qemu_xen[];
>  extern int dsdt_anycpu_qemu_xen_len;
> +extern unsigned short dsdt_anycpu_qemu_xen_aml_ej0_name[];
> +extern unsigned short dsdt_anycpu_qemu_xen_aml_adr_dword[];
> +extern int dsdt_anycpu_qemu_xen_aml_ej0_name_len;
> +extern int dsdt_anycpu_qemu_xen_aml_adr_dword_len;
> 
>  struct seabios_info {
>      char signature[14]; /* XenHVMSeaBIOS\0 */
> @@ -99,6 +103,10 @@ static void seabios_acpi_build_tables(void)
>          .dsdt_anycpu_len = dsdt_anycpu_qemu_xen_len,
>          .dsdt_15cpu = NULL,
>          .dsdt_15cpu_len = 0,
> +        .aml_ej0_name = dsdt_anycpu_qemu_xen_aml_ej0_name,
> +        .aml_adr_dword = dsdt_anycpu_qemu_xen_aml_adr_dword,
> +        .aml_ej0_name_len = dsdt_anycpu_qemu_xen_aml_ej0_name_len,
> +        .aml_adr_dword_len =
> dsdt_anycpu_qemu_xen_aml_adr_dword_len,
>      };
> 
>      acpi_build_tables(&config, rsdp);
> diff --git a/tools/firmware/hvmloader/tools/acpi_extract.py
> b/tools/firmware/hvmloader/tools/acpi_extract.py
> new file mode 100644
> index 0000000..4fa51f7
> --- /dev/null
> +++ b/tools/firmware/hvmloader/tools/acpi_extract.py
> @@ -0,0 +1,308 @@
> +#!/usr/bin/python
> +# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
> +#
> +# This file may be distributed under the terms of the GNU GPLv3 license.
> +
> +# Process mixed ASL/AML listing (.lst file) produced by iasl -l
> +# Locate and execute ACPI_EXTRACT directives, output offset info
> +#
> +# Documentation of ACPI_EXTRACT_* directive tags:
> +#
> +# These directive tags output offset information from AML for BIOS runtime
> +# table generation.
> +# Each directive is of the form:
> +# ACPI_EXTRACT_<TYPE> <array_name> <Operator> (...)
> +# and causes the extractor to create an array
> +# named <array_name> with offset, in the generated AML,
> +# of an object of a given type in the following <Operator>.
> +#
> +# A directive must fit on a single code line.
> +#
> +# Object type in AML is verified, a mismatch causes a build failure.
> +#
> +# Directives and operators currently supported are:
> +# ACPI_EXTRACT_NAME_DWORD_CONST - extract a Dword Const object
> from Name()
> +# ACPI_EXTRACT_NAME_WORD_CONST - extract a Word Const object from
> Name()
> +# ACPI_EXTRACT_NAME_BYTE_CONST - extract a Byte Const object from
> Name()
> +# ACPI_EXTRACT_METHOD_STRING - extract a NameString from Method()
> +# ACPI_EXTRACT_NAME_STRING - extract a NameString from Name()
> +# ACPI_EXTRACT_PROCESSOR_START - start of Processor() block
> +# ACPI_EXTRACT_PROCESSOR_STRING - extract a NameString from
> Processor()
> +# ACPI_EXTRACT_PROCESSOR_END - offset at last byte of Processor() + 1
> +# ACPI_EXTRACT_PKG_START - start of Package block
> +#
> +# ACPI_EXTRACT_ALL_CODE - create an array storing the generated AML
> bytecode
> +#
> +# ACPI_EXTRACT is not allowed anywhere else in code, except in comments.
> +
> +import re;
> +import sys;
> +import fileinput;
> +
> +aml = []
> +asl = []
> +output = {}
> +debug = ""
> +
> +class asl_line:
> +    line = None
> +    lineno = None
> +    aml_offset = None
> +
> +def die(diag):
> +    sys.stderr.write("Error: %s; %s\n" % (diag, debug))
> +    sys.exit(1)
> +
> +#Store an ASL command, matching AML offset, and input line (for debugging)
> +def add_asl(lineno, line):
> +    l = asl_line()
> +    l.line = line
> +    l.lineno = lineno
> +    l.aml_offset = len(aml)
> +    asl.append(l)
> +
> +#Store an AML byte sequence
> +#Verify that offset output by iasl matches # of bytes so far
> +def add_aml(offset, line):
> +    o = int(offset, 16);
> +    # Sanity check: offset must match size of code so far
> +    if (o != len(aml)):
> +        die("Offset 0x%x != 0x%x" % (o, len(aml)))
> +    # Strip any trailing dots and ASCII dump after "
> +    line = re.sub(r'\s*\.*\s*".*$',"", line)
> +    # Strip traling whitespace
> +    line = re.sub(r'\s+$',"", line)
> +    # Strip leading whitespace
> +    line = re.sub(r'^\s+',"", line)
> +    # Split on whitespace
> +    code = re.split(r'\s+', line)
> +    for c in code:
> +        # Require a legal hex number, two digits
> +        if (not(re.search(r'^[0-9A-Fa-f][0-9A-Fa-f]$', c))):
> +            die("Unexpected octet %s" % c);
> +        aml.append(int(c, 16));
> +
> +# Process aml bytecode array, decoding AML
> +def aml_pkglen_bytes(offset):
> +    # PkgLength can be multibyte. Bits 8-7 give the # of extra bytes.
> +    pkglenbytes = aml[offset] >> 6;
> +    return pkglenbytes + 1
> +
> +def aml_pkglen(offset):
> +    pkgstart = offset
> +    pkglenbytes = aml_pkglen_bytes(offset)
> +    pkglen = aml[offset] & 0x3F
> +    # If multibyte, first nibble only uses bits 0-3
> +    if ((pkglenbytes > 0) and (pkglen & 0x30)):
> +        die("PkgLen bytes 0x%x but first nibble 0x%x expected 0x0X" %
> +            (pkglen, pkglen))
> +    offset += 1
> +    pkglenbytes -= 1
> +    for i in range(pkglenbytes):
> +        pkglen |= aml[offset + i] << (i * 8 + 4)
> +    if (len(aml) < pkgstart + pkglen):
> +        die("PckgLen 0x%x at offset 0x%x exceeds AML size 0x%x" %
> +            (pkglen, offset, len(aml)))
> +    return pkglen
> +
> +# Given method offset, find its NameString offset
> +def aml_method_string(offset):
> +    #0x14 MethodOp PkgLength NameString MethodFlags TermList
> +    if (aml[offset] != 0x14):
> +        die( "Method offset 0x%x: expected 0x14 actual 0x%x" %
> +             (offset, aml[offset]));
> +    offset += 1;
> +    pkglenbytes = aml_pkglen_bytes(offset)
> +    offset += pkglenbytes;
> +    return offset;
> +
> +# Given name offset, find its NameString offset
> +def aml_name_string(offset):
> +    #0x08 NameOp NameString DataRef
> +    if (aml[offset] != 0x08):
> +        die( "Name offset 0x%x: expected 0x08 actual 0x%x" %
> +             (offset, aml[offset]));
> +    offset += 1
> +    # Block Name Modifier. Skip it.
> +    if (aml[offset] == 0x5c or aml[offset] == 0x5e):
> +        offset += 1
> +    return offset;
> +
> +# Given data offset, find dword const offset
> +def aml_data_dword_const(offset):
> +    #0x08 NameOp NameString DataRef
> +    if (aml[offset] != 0x0C):
> +        die( "Name offset 0x%x: expected 0x0C actual 0x%x" %
> +             (offset, aml[offset]));
> +    return offset + 1;
> +
> +# Given data offset, find word const offset
> +def aml_data_word_const(offset):
> +    #0x08 NameOp NameString DataRef
> +    if (aml[offset] != 0x0B):
> +        die( "Name offset 0x%x: expected 0x0B actual 0x%x" %
> +             (offset, aml[offset]));
> +    return offset + 1;
> +
> +# Given data offset, find byte const offset
> +def aml_data_byte_const(offset):
> +    #0x08 NameOp NameString DataRef
> +    if (aml[offset] != 0x0A):
> +        die( "Name offset 0x%x: expected 0x0A actual 0x%x" %
> +             (offset, aml[offset]));
> +    return offset + 1;
> +
> +# Given name offset, find dword const offset
> +def aml_name_dword_const(offset):
> +    return aml_data_dword_const(aml_name_string(offset) + 4)
> +
> +# Given name offset, find word const offset
> +def aml_name_word_const(offset):
> +    return aml_data_word_const(aml_name_string(offset) + 4)
> +
> +# Given name offset, find byte const offset
> +def aml_name_byte_const(offset):
> +    return aml_data_byte_const(aml_name_string(offset) + 4)
> +
> +def aml_processor_start(offset):
> +    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
> +    if ((aml[offset] != 0x5B) or (aml[offset + 1] != 0x83)):
> +        die( "Name offset 0x%x: expected 0x5B 0x83 actual 0x%x 0x%x" %
> +             (offset, aml[offset], aml[offset + 1]));
> +    return offset
> +
> +def aml_processor_string(offset):
> +    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
> +    start = aml_processor_start(offset)
> +    offset += 2
> +    pkglenbytes = aml_pkglen_bytes(offset)
> +    offset += pkglenbytes
> +    return offset
> +
> +def aml_processor_end(offset):
> +    start = aml_processor_start(offset)
> +    offset += 2
> +    pkglenbytes = aml_pkglen_bytes(offset)
> +    pkglen = aml_pkglen(offset)
> +    return offset + pkglen
> +
> +def aml_package_start(offset):
> +    offset = aml_name_string(offset) + 4
> +    # 0x12 PkgLength NumElements PackageElementList
> +    if (aml[offset] != 0x12):
> +        die( "Name offset 0x%x: expected 0x12 actual 0x%x" %
> +             (offset, aml[offset]));
> +    offset += 1
> +    return offset + aml_pkglen_bytes(offset) + 1
> +
> +lineno = 0
> +for line in fileinput.input():
> +    # Strip trailing newline
> +    line = line.rstrip();
> +    # line number and debug string to output in case of errors
> +    lineno = lineno + 1
> +    debug = "input line %d: %s" % (lineno, line)
> +    #ASL listing: space, then line#, then ...., then code
> +    pasl = re.compile('^\s+([0-9]+)\.\.\.\.\s*')
> +    m = pasl.search(line)
> +    if (m):
> +        add_asl(lineno, pasl.sub("", line));
> +    # AML listing: offset in hex, then ...., then code
> +    paml = re.compile('^([0-9A-Fa-f]+)\.\.\.\.\s*')
> +    m = paml.search(line)
> +    if (m):
> +        add_aml(m.group(1), paml.sub("", line))
> +
> +# Now go over code
> +# Track AML offset of a previous non-empty ASL command
> +prev_aml_offset = -1
> +for i in range(len(asl)):
> +    debug = "input line %d: %s" % (asl[i].lineno, asl[i].line)
> +
> +    l = asl[i].line
> +
> +    # skip if not an extract directive
> +    a = len(re.findall(r'ACPI_EXTRACT', l))
> +    if (not a):
> +        # If not empty, store AML offset. Will be used for sanity checks
> +        # IASL seems to put {}. at random places in the listing.
> +        # Ignore any non-words for the purpose of this test.
> +        m = re.search(r'\w+', l)
> +        if (m):
> +                prev_aml_offset = asl[i].aml_offset
> +        continue
> +
> +    if (a > 1):
> +        die("Expected at most one ACPI_EXTRACT per line, actual %d" % a)
> +
> +    mext = re.search(r'''
> +                      ^\s* # leading whitespace
> +                      /\*\s* # start C comment
> +                      (ACPI_EXTRACT_\w+) # directive: group(1)
> +                      \s+ # whitspace separates directive from array
> name
> +                      (\w+) # array name: group(2)
> +                      \s*\*/ # end of C comment
> +                      \s*$ # trailing whitespace
> +                      ''', l, re.VERBOSE)
> +    if (not mext):
> +        die("Stray ACPI_EXTRACT in input")
> +
> +    # previous command must have produced some AML,
> +    # otherwise we are in a middle of a block
> +    if (prev_aml_offset == asl[i].aml_offset):
> +        die("ACPI_EXTRACT directive in the middle of a block")
> +
> +    directive = mext.group(1)
> +    array = mext.group(2)
> +    offset = asl[i].aml_offset
> +
> +    if (directive == "ACPI_EXTRACT_ALL_CODE"):
> +        if array in output:
> +            die("%s directive used more than once" % directive)
> +        output[array] = aml
> +        continue
> +    if (directive == "ACPI_EXTRACT_NAME_DWORD_CONST"):
> +        offset = aml_name_dword_const(offset)
> +    elif (directive == "ACPI_EXTRACT_NAME_WORD_CONST"):
> +        offset = aml_name_word_const(offset)
> +    elif (directive == "ACPI_EXTRACT_NAME_BYTE_CONST"):
> +        offset = aml_name_byte_const(offset)
> +    elif (directive == "ACPI_EXTRACT_NAME_STRING"):
> +        offset = aml_name_string(offset)
> +    elif (directive == "ACPI_EXTRACT_METHOD_STRING"):
> +        offset = aml_method_string(offset)
> +    elif (directive == "ACPI_EXTRACT_PROCESSOR_START"):
> +        offset = aml_processor_start(offset)
> +    elif (directive == "ACPI_EXTRACT_PROCESSOR_STRING"):
> +        offset = aml_processor_string(offset)
> +    elif (directive == "ACPI_EXTRACT_PROCESSOR_END"):
> +        offset = aml_processor_end(offset)
> +    elif (directive == "ACPI_EXTRACT_PKG_START"):
> +        offset = aml_package_start(offset)
> +    else:
> +        die("Unsupported directive %s" % directive)
> +
> +    if array not in output:
> +        output[array] = []
> +    output[array].append(offset)
> +
> +debug = "at end of file"
> +
> +def get_value_type(maxvalue):
> +    #Use type large enough to fit the table
> +    if (maxvalue >= 0x10000):
> +            return "int"
> +    elif (maxvalue >= 0x100):
> +            return "short"
> +    else:
> +            return "char"
> +
> +# Pretty print output
> +for array in output.keys():
> +    otype = get_value_type(max(output[array]))
> +    odata = []
> +    for value in output[array]:
> +        odata.append("0x%x" % value)
> +    sys.stdout.write("unsigned %s %s[] = {\n" % (otype, array))
> +    sys.stdout.write(",\n".join(odata))
> +    sys.stdout.write('\n};\n');
> diff --git a/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py
> b/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py
> new file mode 100644
> index 0000000..4ae364e
> --- /dev/null
> +++ b/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py
> @@ -0,0 +1,41 @@
> +#!/usr/bin/python
> +# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
> +#
> +# This file may be distributed under the terms of the GNU GPLv3 license.
> +
> +# Read a preprocessed ASL listing and put each ACPI_EXTRACT
> +# directive in a comment, to make iasl skip it.
> +# We also put each directive on a new line, the machinery
> +# in tools/acpi_extract.py requires this.
> +
> +import re;
> +import sys;
> +import fileinput;
> +
> +def die(diag):
> +    sys.stderr.write("Error: %s\n" % (diag))
> +    sys.exit(1)
> +
> +# Note: () around pattern make split return matched string as part of list
> +psplit = re.compile(r''' (
> +                          \b # At word boundary
> +                          ACPI_EXTRACT_\w+ # directive
> +                          \s+ # some whitespace
> +                          \w+ # array name
> +                         )''', re.VERBOSE);
> +
> +lineno = 0
> +for line in fileinput.input():
> +    # line number and debug string to output in case of errors
> +    lineno = lineno + 1
> +    debug = "input line %d: %s" % (lineno, line.rstrip())
> +
> +    s = psplit.split(line);
> +    # The way split works, each odd item is the matching ACPI_EXTRACT
> directive.
> +    # Put each in a comment, and on a line by itself.
> +    for i in range(len(s)):
> +        if (i % 2):
> +            sys.stdout.write("\n/* %s */\n" % s[i])
> +        else:
> +            sys.stdout.write(s[i])
> +
> --
> 1.8.3.4
> 


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
  2013-10-22  8:06               ` [Qemu-devel] [Xen-devel] " Jan Beulich
  2013-10-24 12:17                 ` [Qemu-devel] " Gonglei (Arei)
  2013-10-24 12:17                 ` [Qemu-devel] [Xen-devel] " Gonglei (Arei)
@ 2013-10-28  7:14                 ` Gonglei (Arei)
  2013-10-28  7:14                 ` [Qemu-devel] [Xen-devel] " Gonglei (Arei)
  3 siblings, 0 replies; 38+ messages in thread
From: Gonglei (Arei) @ 2013-10-28  7:14 UTC (permalink / raw)
  To: Gonglei (Arei), Jan Beulich
  Cc: Yanqiangjun, Ian Campbell, Hanweidong (Randy),
	Markus Armbruster, Stefano Stabellini, Luonengjun, qemu-devel,
	xen-devel, Fabio Fantoni, anthony.perard, Gaowei (UVP),
	Huangweidong (Hardware)

Hi,

Please post any comments or questions if you get around to testing them. 
Your comments are very welcome!

Best regards,
-Gonglei

> > >>> On 22.10.13 at 06:08, "Gonglei (Arei)" <arei.gonglei@huawei.com>
> wrote:
> > > Hi, guys. The new patch has been modified based on the principles you
> > > suggested, thank you so much.
> > > Last time I test the patch based on the codes of 4.3.0.
> > > This time, I found that the system based on the codes of trunk causes the
> VM
> > > reboot again and again, which I have not found out the reason.
> > > So i can not test the patch based on the codes of trunk (details in
> > > EJ0_ACPI_PCI_Hotplug.patch)..
> >
> > I'm afraid we will need you to figure out that problem first, and
> > then do the verification on -unstable. Even if the code shouldn't
> > be that different from 4.3, we still don't want to apply completely
> > untested stuff.
> 
> Hi, Jan. We found that the reason that we used a wrong seabios PATH, and the
> hvmloader can't load the bios.bin.
> So the VM restart again and again after we start it. That's our fault.
> 
> Now I test the patch based on the codes of trunk, which works well.
> The patch has been modified after your suggestion.
> The patch works well with upstream qemu and doesn't affect the system with
> traditional qemu.
> 
> >
> >
> > > --- a/tools/firmware/hvmloader/ovmf.c
> > > +++ b/tools/firmware/hvmloader/ovmf.c
> > > @@ -79,7 +79,11 @@ static void ovmf_acpi_build_tables(void)
> > >          .dsdt_anycpu = dsdt_anycpu,
> > >          .dsdt_anycpu_len = dsdt_anycpu_len,
> > >          .dsdt_15cpu = NULL,
> > > -        .dsdt_15cpu_len = 0
> > > +        .dsdt_15cpu_len = 0,
> > > +        .aml_ej0_name = NULL,
> > > +        .aml_adr_dword = NULL,
> > > +        .aml_ej0_name_len = 0,
> > > +        .aml_adr_dword_len = 0,
> >
> > I don't see why you're adding these.
> >
> Insurance purposes is that just initialize the struct.
> 
> Signed-off-by: Gaowei <gao.gaowei@huawei.com>
> Signed-off-by: gonglei <arei.gonglei@huawei.com>
> ---
>  tools/firmware/hvmloader/acpi/Makefile             |  37 ++-
>  tools/firmware/hvmloader/acpi/acpi2_0.h            |   4 +
>  tools/firmware/hvmloader/acpi/build.c              |  21 +-
>  tools/firmware/hvmloader/acpi/dsdt.asl             |   1 +
>  tools/firmware/hvmloader/acpi/mk_dsdt.c            |   2 +
>  tools/firmware/hvmloader/ovmf.c                    |   6 +-
>  tools/firmware/hvmloader/rombios.c                 |   4 +
>  tools/firmware/hvmloader/seabios.c                 |   8 +
>  tools/firmware/hvmloader/tools/acpi_extract.py     | 308
> +++++++++++++++++++++
>  .../hvmloader/tools/acpi_extract_preprocess.py     |  41 +++
>  10 files changed, 419 insertions(+), 13 deletions(-)
>  create mode 100644 tools/firmware/hvmloader/tools/acpi_extract.py
>  create mode 100644
> tools/firmware/hvmloader/tools/acpi_extract_preprocess.py
> 
> diff --git a/tools/firmware/hvmloader/acpi/Makefile
> b/tools/firmware/hvmloader/acpi/Makefile
> index 2c50851..b96e058 100644
> --- a/tools/firmware/hvmloader/acpi/Makefile
> +++ b/tools/firmware/hvmloader/acpi/Makefile
> @@ -24,30 +24,45 @@ OBJS  = $(patsubst %.c,%.o,$(C_SRC))
>  CFLAGS += $(CFLAGS_xeninclude)
> 
>  vpath iasl $(PATH)
> +
> +.DELETE_ON_ERROR: $(filter dsdt_%.c,$(C_SRC))
> +
>  all: acpi.a
> 
>  ssdt_s3.h ssdt_s4.h ssdt_pm.h ssdt_tpm.h: %.h: %.asl iasl
>  	iasl -vs -p $* -tc $<
> -	sed -e 's/AmlCode/$*/g' $*.hex >$@
> +	sed -e 's/AmlCode/$*/g' $*.hex > $@.tmp
> +	$(call move-if-changed,$@.tmp $@)
>  	rm -f $*.hex $*.aml
> 
>  mk_dsdt: mk_dsdt.c
>  	$(HOSTCC) $(HOSTCFLAGS) $(CFLAGS_xeninclude) -o $@ mk_dsdt.c
> 
>  dsdt_anycpu_qemu_xen.asl: dsdt.asl mk_dsdt
> -	awk 'NR > 1 {print s} {s=$$0}' $< > $@
> -	./mk_dsdt --dm-version qemu-xen >> $@
> +	awk 'NR > 1 {print s} {s=$$0}' $< > $@.tmp
> +	sed -i 's/AmlCode/dsdt_anycpu_qemu_xen/g' $@.tmp
> +	./mk_dsdt --dm-version qemu-xen >> $@.tmp
> +	sed -i 's/aml_ej0_name/dsdt_anycpu_qemu_xen_aml_ej0_name/g'
> $@.tmp
> +	sed -i 's/aml_adr_dword/dsdt_anycpu_qemu_xen_aml_adr_dword/g'
> $@.tmp
> +	$(call move-if-changed,$@.tmp $@)
> 
>  # NB. awk invocation is a portable alternative to 'head -n -1'
>  dsdt_%cpu.asl: dsdt.asl mk_dsdt
> -	awk 'NR > 1 {print s} {s=$$0}' $< > $@
> -	./mk_dsdt --maxcpu $*  >> $@
> +	awk 'NR > 1 {print s} {s=$$0}' $< > $@.tmp
> +	sed -i 's/AmlCode/dsdt_$*cpu/g' $@.tmp
> +	./mk_dsdt --maxcpu $*  >> $@.tmp
> +	$(call move-if-changed,$@.tmp $@)
> 
> -$(filter dsdt_%.c,$(C_SRC)): %.c: iasl %.asl
> -	iasl -vs -p $* -tc $*.asl
> -	sed -e 's/AmlCode/$*/g' $*.hex >$@
> -	echo "int $*_len=sizeof($*);" >>$@
> -	rm -f $*.aml $*.hex
> +$(filter dsdt_%.c,$(C_SRC)): %.c: %.asl iasl
> +	cpp -P $< > $<.i.orig
> +	$(PYTHON) ../tools/acpi_extract_preprocess.py $<.i.orig > $<.i
> +	iasl -vs -l -tc -p $* $<.i
> +	$(PYTHON) ../tools/acpi_extract.py $*.lst > $@.tmp
> +	echo "int $*_len=sizeof($*);" >> $@.tmp
> +	if grep -q "$*_aml_ej0_name" $@.tmp; then echo "int
> $*_aml_ej0_name_len=sizeof($*_aml_ej0_name);" >> $@.tmp; fi
> +	if grep -q "$*_aml_adr_dword" $@.tmp; then echo "int
> $*_aml_adr_dword_len=sizeof($*_aml_adr_dword);" >> $@.tmp; fi
> +	$(call move-if-changed,$@.tmp $@)
> +	rm -f $*.aml $*.hex $*.asl.i.orig $*.asl.i $*.lst
> 
>  iasl:
>  	@echo
> @@ -64,7 +79,7 @@ acpi.a: $(OBJS)
> 
>  clean:
>  	rm -rf *.a *.o $(IASL_VER) $(IASL_VER).tar.gz $(DEPS)
> -	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl
> +	rm -rf ssdt_*.h dsdt*.c *~ *.aml *.hex mk_dsdt dsdt_*.asl *.asl.i
> *.asl.i.orig *.lst *.tmp
> 
>  install: all
> 
> diff --git a/tools/firmware/hvmloader/acpi/acpi2_0.h
> b/tools/firmware/hvmloader/acpi/acpi2_0.h
> index 7b22d80..4ba3957 100644
> --- a/tools/firmware/hvmloader/acpi/acpi2_0.h
> +++ b/tools/firmware/hvmloader/acpi/acpi2_0.h
> @@ -396,6 +396,10 @@ struct acpi_config {
>      int dsdt_anycpu_len;
>      unsigned char *dsdt_15cpu;
>      int dsdt_15cpu_len;
> +    unsigned short *aml_ej0_name;
> +    unsigned short *aml_adr_dword;
> +    int aml_ej0_name_len;
> +    int aml_adr_dword_len;
>  };
> 
>  void acpi_build_tables(struct acpi_config *config, unsigned int physical);
> diff --git a/tools/firmware/hvmloader/acpi/build.c
> b/tools/firmware/hvmloader/acpi/build.c
> index f1dd3f0..7eb21d3 100644
> --- a/tools/firmware/hvmloader/acpi/build.c
> +++ b/tools/firmware/hvmloader/acpi/build.c
> @@ -29,6 +29,7 @@
> 
>  #define align16(sz)        (((sz) + 15) & ~15)
>  #define fixed_strcpy(d, s) strncpy((d), (s), sizeof(d))
> +#define PCI_RMV_BASE 0xae0c
> 
>  extern struct acpi_20_rsdp Rsdp;
>  extern struct acpi_20_rsdt Rsdt;
> @@ -404,6 +405,7 @@ void acpi_build_tables(struct acpi_config *config,
> unsigned int physical)
>      unsigned char       *dsdt;
>      unsigned long
> secondary_tables[ACPI_MAX_SECONDARY_TABLES];
>      int                  nr_secondaries, i;
> +    unsigned int rmvc_pcrm = 0;
> 
>      /* Allocate and initialise the acpi info area. */
>      mem_hole_populate_ram(ACPI_INFO_PHYSICAL_ADDRESS >>
> PAGE_SHIFT, 1);
> @@ -440,7 +442,24 @@ void acpi_build_tables(struct acpi_config *config,
> unsigned int physical)
>          memcpy(dsdt, config->dsdt_anycpu, config->dsdt_anycpu_len);
>          nr_processor_objects = HVM_MAX_VCPUS;
>      }
> -
> +    if(config->aml_adr_dword_len && config->aml_ej0_name_len &&
> +        (config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]) ==
> config->aml_ej0_name_len/sizeof(config->aml_ej0_name[0])))
> +    {
> +        rmvc_pcrm = inl(PCI_RMV_BASE);
> +        for(i = 0;  i <
> config->aml_adr_dword_len/sizeof(config->aml_adr_dword[0]); i ++)
> +        {
> +            /* Slot is in byte 2 in _ADR */
> +            unsigned char slot = dsdt[config->aml_adr_dword[i] + 2] &
> 0x1F;
> +            /* Sanity check */
> +            if (memcmp(dsdt + config->aml_ej0_name[i], "_EJ0", 4)) {
> +                printf("Method '_EJ0' can not be found for pci slot %d\n",
> slot);
> +                return;
> +            }
> +            if (!(rmvc_pcrm & (0x1 << slot))) {
> +                memcpy(dsdt + config->aml_ej0_name[i], "EJ0_", 4);
> +            }
> +        }
> +    }
>      /*
>       * N.B. ACPI 1.0 operating systems may not handle FADT with revision 2
>       * or above properly, notably Windows 2000, which tries to copy FADT
> diff --git a/tools/firmware/hvmloader/acpi/dsdt.asl
> b/tools/firmware/hvmloader/acpi/dsdt.asl
> index 247a8ad..1e7695b 100644
> --- a/tools/firmware/hvmloader/acpi/dsdt.asl
> +++ b/tools/firmware/hvmloader/acpi/dsdt.asl
> @@ -16,6 +16,7 @@
>   * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
>   * Place - Suite 330, Boston, MA 02111-1307 USA.
>   */
> +ACPI_EXTRACT_ALL_CODE AmlCode
> 
>  DefinitionBlock ("DSDT.aml", "DSDT", 2, "Xen", "HVM", 0)
>  {
> diff --git a/tools/firmware/hvmloader/acpi/mk_dsdt.c
> b/tools/firmware/hvmloader/acpi/mk_dsdt.c
> index 996f30b..4180801 100644
> --- a/tools/firmware/hvmloader/acpi/mk_dsdt.c
> +++ b/tools/firmware/hvmloader/acpi/mk_dsdt.c
> @@ -368,7 +368,9 @@ int main(int argc, char **argv)
>          /* hotplug_slot */
>          for (slot = 1; slot <= 31; slot++) {
>              push_block("Device", "S%i", slot); {
> +                printf("ACPI_EXTRACT_NAME_DWORD_CONST
> aml_adr_dword\n");
>                  stmt("Name", "_ADR, %#06x0000", slot);
> +                printf("ACPI_EXTRACT_METHOD_STRING
> aml_ej0_name\n");
>                  push_block("Method", "_EJ0,1"); {
>                      stmt("Store", "ShiftLeft(1, %#06x), B0EJ", slot);
>                      stmt("Return", "0x0");
> diff --git a/tools/firmware/hvmloader/ovmf.c
> b/tools/firmware/hvmloader/ovmf.c
> index ee4cbbf..27ff0b5 100644
> --- a/tools/firmware/hvmloader/ovmf.c
> +++ b/tools/firmware/hvmloader/ovmf.c
> @@ -79,7 +79,11 @@ static void ovmf_acpi_build_tables(void)
>          .dsdt_anycpu = dsdt_anycpu,
>          .dsdt_anycpu_len = dsdt_anycpu_len,
>          .dsdt_15cpu = NULL,
> -        .dsdt_15cpu_len = 0
> +        .dsdt_15cpu_len = 0,
> +        .aml_ej0_name = NULL,
> +        .aml_adr_dword = NULL,
> +        .aml_ej0_name_len = 0,
> +        .aml_adr_dword_len = 0,
>      };
> 
>      acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
> diff --git a/tools/firmware/hvmloader/rombios.c
> b/tools/firmware/hvmloader/rombios.c
> index 810bd24..803c9fa 100644
> --- a/tools/firmware/hvmloader/rombios.c
> +++ b/tools/firmware/hvmloader/rombios.c
> @@ -179,6 +179,10 @@ static void rombios_acpi_build_tables(void)
>          .dsdt_anycpu_len = dsdt_anycpu_len,
>          .dsdt_15cpu = dsdt_15cpu,
>          .dsdt_15cpu_len = dsdt_15cpu_len,
> +        .aml_ej0_name = NULL,
> +        .aml_adr_dword = NULL,
> +        .aml_ej0_name_len = 0,
> +        .aml_adr_dword_len = 0,
>      };
> 
>      acpi_build_tables(&config, ACPI_PHYSICAL_ADDRESS);
> diff --git a/tools/firmware/hvmloader/seabios.c
> b/tools/firmware/hvmloader/seabios.c
> index dd7dfbe..ca01d27 100644
> --- a/tools/firmware/hvmloader/seabios.c
> +++ b/tools/firmware/hvmloader/seabios.c
> @@ -33,6 +33,10 @@
> 
>  extern unsigned char dsdt_anycpu_qemu_xen[];
>  extern int dsdt_anycpu_qemu_xen_len;
> +extern unsigned short dsdt_anycpu_qemu_xen_aml_ej0_name[];
> +extern unsigned short dsdt_anycpu_qemu_xen_aml_adr_dword[];
> +extern int dsdt_anycpu_qemu_xen_aml_ej0_name_len;
> +extern int dsdt_anycpu_qemu_xen_aml_adr_dword_len;
> 
>  struct seabios_info {
>      char signature[14]; /* XenHVMSeaBIOS\0 */
> @@ -99,6 +103,10 @@ static void seabios_acpi_build_tables(void)
>          .dsdt_anycpu_len = dsdt_anycpu_qemu_xen_len,
>          .dsdt_15cpu = NULL,
>          .dsdt_15cpu_len = 0,
> +        .aml_ej0_name = dsdt_anycpu_qemu_xen_aml_ej0_name,
> +        .aml_adr_dword = dsdt_anycpu_qemu_xen_aml_adr_dword,
> +        .aml_ej0_name_len = dsdt_anycpu_qemu_xen_aml_ej0_name_len,
> +        .aml_adr_dword_len =
> dsdt_anycpu_qemu_xen_aml_adr_dword_len,
>      };
> 
>      acpi_build_tables(&config, rsdp);
> diff --git a/tools/firmware/hvmloader/tools/acpi_extract.py
> b/tools/firmware/hvmloader/tools/acpi_extract.py
> new file mode 100644
> index 0000000..4fa51f7
> --- /dev/null
> +++ b/tools/firmware/hvmloader/tools/acpi_extract.py
> @@ -0,0 +1,308 @@
> +#!/usr/bin/python
> +# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
> +#
> +# This file may be distributed under the terms of the GNU GPLv3 license.
> +
> +# Process mixed ASL/AML listing (.lst file) produced by iasl -l
> +# Locate and execute ACPI_EXTRACT directives, output offset info
> +#
> +# Documentation of ACPI_EXTRACT_* directive tags:
> +#
> +# These directive tags output offset information from AML for BIOS runtime
> +# table generation.
> +# Each directive is of the form:
> +# ACPI_EXTRACT_<TYPE> <array_name> <Operator> (...)
> +# and causes the extractor to create an array
> +# named <array_name> with offset, in the generated AML,
> +# of an object of a given type in the following <Operator>.
> +#
> +# A directive must fit on a single code line.
> +#
> +# Object type in AML is verified, a mismatch causes a build failure.
> +#
> +# Directives and operators currently supported are:
> +# ACPI_EXTRACT_NAME_DWORD_CONST - extract a Dword Const object
> from Name()
> +# ACPI_EXTRACT_NAME_WORD_CONST - extract a Word Const object from
> Name()
> +# ACPI_EXTRACT_NAME_BYTE_CONST - extract a Byte Const object from
> Name()
> +# ACPI_EXTRACT_METHOD_STRING - extract a NameString from Method()
> +# ACPI_EXTRACT_NAME_STRING - extract a NameString from Name()
> +# ACPI_EXTRACT_PROCESSOR_START - start of Processor() block
> +# ACPI_EXTRACT_PROCESSOR_STRING - extract a NameString from
> Processor()
> +# ACPI_EXTRACT_PROCESSOR_END - offset at last byte of Processor() + 1
> +# ACPI_EXTRACT_PKG_START - start of Package block
> +#
> +# ACPI_EXTRACT_ALL_CODE - create an array storing the generated AML
> bytecode
> +#
> +# ACPI_EXTRACT is not allowed anywhere else in code, except in comments.
> +
> +import re;
> +import sys;
> +import fileinput;
> +
> +aml = []
> +asl = []
> +output = {}
> +debug = ""
> +
> +class asl_line:
> +    line = None
> +    lineno = None
> +    aml_offset = None
> +
> +def die(diag):
> +    sys.stderr.write("Error: %s; %s\n" % (diag, debug))
> +    sys.exit(1)
> +
> +#Store an ASL command, matching AML offset, and input line (for debugging)
> +def add_asl(lineno, line):
> +    l = asl_line()
> +    l.line = line
> +    l.lineno = lineno
> +    l.aml_offset = len(aml)
> +    asl.append(l)
> +
> +#Store an AML byte sequence
> +#Verify that offset output by iasl matches # of bytes so far
> +def add_aml(offset, line):
> +    o = int(offset, 16);
> +    # Sanity check: offset must match size of code so far
> +    if (o != len(aml)):
> +        die("Offset 0x%x != 0x%x" % (o, len(aml)))
> +    # Strip any trailing dots and ASCII dump after "
> +    line = re.sub(r'\s*\.*\s*".*$',"", line)
> +    # Strip traling whitespace
> +    line = re.sub(r'\s+$',"", line)
> +    # Strip leading whitespace
> +    line = re.sub(r'^\s+',"", line)
> +    # Split on whitespace
> +    code = re.split(r'\s+', line)
> +    for c in code:
> +        # Require a legal hex number, two digits
> +        if (not(re.search(r'^[0-9A-Fa-f][0-9A-Fa-f]$', c))):
> +            die("Unexpected octet %s" % c);
> +        aml.append(int(c, 16));
> +
> +# Process aml bytecode array, decoding AML
> +def aml_pkglen_bytes(offset):
> +    # PkgLength can be multibyte. Bits 8-7 give the # of extra bytes.
> +    pkglenbytes = aml[offset] >> 6;
> +    return pkglenbytes + 1
> +
> +def aml_pkglen(offset):
> +    pkgstart = offset
> +    pkglenbytes = aml_pkglen_bytes(offset)
> +    pkglen = aml[offset] & 0x3F
> +    # If multibyte, first nibble only uses bits 0-3
> +    if ((pkglenbytes > 0) and (pkglen & 0x30)):
> +        die("PkgLen bytes 0x%x but first nibble 0x%x expected 0x0X" %
> +            (pkglen, pkglen))
> +    offset += 1
> +    pkglenbytes -= 1
> +    for i in range(pkglenbytes):
> +        pkglen |= aml[offset + i] << (i * 8 + 4)
> +    if (len(aml) < pkgstart + pkglen):
> +        die("PckgLen 0x%x at offset 0x%x exceeds AML size 0x%x" %
> +            (pkglen, offset, len(aml)))
> +    return pkglen
> +
> +# Given method offset, find its NameString offset
> +def aml_method_string(offset):
> +    #0x14 MethodOp PkgLength NameString MethodFlags TermList
> +    if (aml[offset] != 0x14):
> +        die( "Method offset 0x%x: expected 0x14 actual 0x%x" %
> +             (offset, aml[offset]));
> +    offset += 1;
> +    pkglenbytes = aml_pkglen_bytes(offset)
> +    offset += pkglenbytes;
> +    return offset;
> +
> +# Given name offset, find its NameString offset
> +def aml_name_string(offset):
> +    #0x08 NameOp NameString DataRef
> +    if (aml[offset] != 0x08):
> +        die( "Name offset 0x%x: expected 0x08 actual 0x%x" %
> +             (offset, aml[offset]));
> +    offset += 1
> +    # Block Name Modifier. Skip it.
> +    if (aml[offset] == 0x5c or aml[offset] == 0x5e):
> +        offset += 1
> +    return offset;
> +
> +# Given data offset, find dword const offset
> +def aml_data_dword_const(offset):
> +    #0x08 NameOp NameString DataRef
> +    if (aml[offset] != 0x0C):
> +        die( "Name offset 0x%x: expected 0x0C actual 0x%x" %
> +             (offset, aml[offset]));
> +    return offset + 1;
> +
> +# Given data offset, find word const offset
> +def aml_data_word_const(offset):
> +    #0x08 NameOp NameString DataRef
> +    if (aml[offset] != 0x0B):
> +        die( "Name offset 0x%x: expected 0x0B actual 0x%x" %
> +             (offset, aml[offset]));
> +    return offset + 1;
> +
> +# Given data offset, find byte const offset
> +def aml_data_byte_const(offset):
> +    #0x08 NameOp NameString DataRef
> +    if (aml[offset] != 0x0A):
> +        die( "Name offset 0x%x: expected 0x0A actual 0x%x" %
> +             (offset, aml[offset]));
> +    return offset + 1;
> +
> +# Given name offset, find dword const offset
> +def aml_name_dword_const(offset):
> +    return aml_data_dword_const(aml_name_string(offset) + 4)
> +
> +# Given name offset, find word const offset
> +def aml_name_word_const(offset):
> +    return aml_data_word_const(aml_name_string(offset) + 4)
> +
> +# Given name offset, find byte const offset
> +def aml_name_byte_const(offset):
> +    return aml_data_byte_const(aml_name_string(offset) + 4)
> +
> +def aml_processor_start(offset):
> +    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
> +    if ((aml[offset] != 0x5B) or (aml[offset + 1] != 0x83)):
> +        die( "Name offset 0x%x: expected 0x5B 0x83 actual 0x%x 0x%x" %
> +             (offset, aml[offset], aml[offset + 1]));
> +    return offset
> +
> +def aml_processor_string(offset):
> +    #0x5B 0x83 ProcessorOp PkgLength NameString ProcID
> +    start = aml_processor_start(offset)
> +    offset += 2
> +    pkglenbytes = aml_pkglen_bytes(offset)
> +    offset += pkglenbytes
> +    return offset
> +
> +def aml_processor_end(offset):
> +    start = aml_processor_start(offset)
> +    offset += 2
> +    pkglenbytes = aml_pkglen_bytes(offset)
> +    pkglen = aml_pkglen(offset)
> +    return offset + pkglen
> +
> +def aml_package_start(offset):
> +    offset = aml_name_string(offset) + 4
> +    # 0x12 PkgLength NumElements PackageElementList
> +    if (aml[offset] != 0x12):
> +        die( "Name offset 0x%x: expected 0x12 actual 0x%x" %
> +             (offset, aml[offset]));
> +    offset += 1
> +    return offset + aml_pkglen_bytes(offset) + 1
> +
> +lineno = 0
> +for line in fileinput.input():
> +    # Strip trailing newline
> +    line = line.rstrip();
> +    # line number and debug string to output in case of errors
> +    lineno = lineno + 1
> +    debug = "input line %d: %s" % (lineno, line)
> +    #ASL listing: space, then line#, then ...., then code
> +    pasl = re.compile('^\s+([0-9]+)\.\.\.\.\s*')
> +    m = pasl.search(line)
> +    if (m):
> +        add_asl(lineno, pasl.sub("", line));
> +    # AML listing: offset in hex, then ...., then code
> +    paml = re.compile('^([0-9A-Fa-f]+)\.\.\.\.\s*')
> +    m = paml.search(line)
> +    if (m):
> +        add_aml(m.group(1), paml.sub("", line))
> +
> +# Now go over code
> +# Track AML offset of a previous non-empty ASL command
> +prev_aml_offset = -1
> +for i in range(len(asl)):
> +    debug = "input line %d: %s" % (asl[i].lineno, asl[i].line)
> +
> +    l = asl[i].line
> +
> +    # skip if not an extract directive
> +    a = len(re.findall(r'ACPI_EXTRACT', l))
> +    if (not a):
> +        # If not empty, store AML offset. Will be used for sanity checks
> +        # IASL seems to put {}. at random places in the listing.
> +        # Ignore any non-words for the purpose of this test.
> +        m = re.search(r'\w+', l)
> +        if (m):
> +                prev_aml_offset = asl[i].aml_offset
> +        continue
> +
> +    if (a > 1):
> +        die("Expected at most one ACPI_EXTRACT per line, actual %d" % a)
> +
> +    mext = re.search(r'''
> +                      ^\s* # leading whitespace
> +                      /\*\s* # start C comment
> +                      (ACPI_EXTRACT_\w+) # directive: group(1)
> +                      \s+ # whitspace separates directive from array
> name
> +                      (\w+) # array name: group(2)
> +                      \s*\*/ # end of C comment
> +                      \s*$ # trailing whitespace
> +                      ''', l, re.VERBOSE)
> +    if (not mext):
> +        die("Stray ACPI_EXTRACT in input")
> +
> +    # previous command must have produced some AML,
> +    # otherwise we are in a middle of a block
> +    if (prev_aml_offset == asl[i].aml_offset):
> +        die("ACPI_EXTRACT directive in the middle of a block")
> +
> +    directive = mext.group(1)
> +    array = mext.group(2)
> +    offset = asl[i].aml_offset
> +
> +    if (directive == "ACPI_EXTRACT_ALL_CODE"):
> +        if array in output:
> +            die("%s directive used more than once" % directive)
> +        output[array] = aml
> +        continue
> +    if (directive == "ACPI_EXTRACT_NAME_DWORD_CONST"):
> +        offset = aml_name_dword_const(offset)
> +    elif (directive == "ACPI_EXTRACT_NAME_WORD_CONST"):
> +        offset = aml_name_word_const(offset)
> +    elif (directive == "ACPI_EXTRACT_NAME_BYTE_CONST"):
> +        offset = aml_name_byte_const(offset)
> +    elif (directive == "ACPI_EXTRACT_NAME_STRING"):
> +        offset = aml_name_string(offset)
> +    elif (directive == "ACPI_EXTRACT_METHOD_STRING"):
> +        offset = aml_method_string(offset)
> +    elif (directive == "ACPI_EXTRACT_PROCESSOR_START"):
> +        offset = aml_processor_start(offset)
> +    elif (directive == "ACPI_EXTRACT_PROCESSOR_STRING"):
> +        offset = aml_processor_string(offset)
> +    elif (directive == "ACPI_EXTRACT_PROCESSOR_END"):
> +        offset = aml_processor_end(offset)
> +    elif (directive == "ACPI_EXTRACT_PKG_START"):
> +        offset = aml_package_start(offset)
> +    else:
> +        die("Unsupported directive %s" % directive)
> +
> +    if array not in output:
> +        output[array] = []
> +    output[array].append(offset)
> +
> +debug = "at end of file"
> +
> +def get_value_type(maxvalue):
> +    #Use type large enough to fit the table
> +    if (maxvalue >= 0x10000):
> +            return "int"
> +    elif (maxvalue >= 0x100):
> +            return "short"
> +    else:
> +            return "char"
> +
> +# Pretty print output
> +for array in output.keys():
> +    otype = get_value_type(max(output[array]))
> +    odata = []
> +    for value in output[array]:
> +        odata.append("0x%x" % value)
> +    sys.stdout.write("unsigned %s %s[] = {\n" % (otype, array))
> +    sys.stdout.write(",\n".join(odata))
> +    sys.stdout.write('\n};\n');
> diff --git a/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py
> b/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py
> new file mode 100644
> index 0000000..4ae364e
> --- /dev/null
> +++ b/tools/firmware/hvmloader/tools/acpi_extract_preprocess.py
> @@ -0,0 +1,41 @@
> +#!/usr/bin/python
> +# Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <mst@redhat.com>
> +#
> +# This file may be distributed under the terms of the GNU GPLv3 license.
> +
> +# Read a preprocessed ASL listing and put each ACPI_EXTRACT
> +# directive in a comment, to make iasl skip it.
> +# We also put each directive on a new line, the machinery
> +# in tools/acpi_extract.py requires this.
> +
> +import re;
> +import sys;
> +import fileinput;
> +
> +def die(diag):
> +    sys.stderr.write("Error: %s\n" % (diag))
> +    sys.exit(1)
> +
> +# Note: () around pattern make split return matched string as part of list
> +psplit = re.compile(r''' (
> +                          \b # At word boundary
> +                          ACPI_EXTRACT_\w+ # directive
> +                          \s+ # some whitespace
> +                          \w+ # array name
> +                         )''', re.VERBOSE);
> +
> +lineno = 0
> +for line in fileinput.input():
> +    # line number and debug string to output in case of errors
> +    lineno = lineno + 1
> +    debug = "input line %d: %s" % (lineno, line.rstrip())
> +
> +    s = psplit.split(line);
> +    # The way split works, each odd item is the matching ACPI_EXTRACT
> directive.
> +    # Put each in a comment, and on a line by itself.
> +    for i in range(len(s)):
> +        if (i % 2):
> +            sys.stdout.write("\n/* %s */\n" % s[i])
> +        else:
> +            sys.stdout.write(s[i])
> +
> --
> 1.8.3.4
> 

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [Xen-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
  2013-10-24 12:17                 ` [Qemu-devel] [Xen-devel] " Gonglei (Arei)
                                     ` (2 preceding siblings ...)
  2013-10-28  9:38                   ` Jan Beulich
@ 2013-10-28  9:38                   ` Jan Beulich
  2014-01-22 14:32                     ` Fabio Fantoni
  2014-01-22 14:32                     ` Fabio Fantoni
  3 siblings, 2 replies; 38+ messages in thread
From: Jan Beulich @ 2013-10-28  9:38 UTC (permalink / raw)
  To: Gonglei (Arei)
  Cc: Yanqiangjun, Ian Campbell, Hanweidong (Randy),
	Markus Armbruster, Stefano Stabellini, Luonengjun, qemu-devel,
	xen-devel, Fabio Fantoni, anthony.perard, Gaowei (UVP),
	Huangweidong (Hardware)

>>> On 24.10.13 at 14:17, "Gonglei (Arei)" <arei.gonglei@huawei.com> wrote:
> Now I test the patch based on the codes of trunk, which works well.
> The patch has been modified after your suggestion.

Partly. I looks reasonable now, but still not pretty. But the tools
maintainers will have to have the final say here anyway.

Jan

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
  2013-10-24 12:17                 ` [Qemu-devel] [Xen-devel] " Gonglei (Arei)
  2013-10-24 12:57                   ` Fabio Fantoni
  2013-10-24 12:57                   ` [Qemu-devel] " Fabio Fantoni
@ 2013-10-28  9:38                   ` Jan Beulich
  2013-10-28  9:38                   ` [Qemu-devel] [Xen-devel] " Jan Beulich
  3 siblings, 0 replies; 38+ messages in thread
From: Jan Beulich @ 2013-10-28  9:38 UTC (permalink / raw)
  To: Gonglei (Arei)
  Cc: Yanqiangjun, Ian Campbell, Hanweidong (Randy),
	Markus Armbruster, Stefano Stabellini, Luonengjun, qemu-devel,
	xen-devel, Fabio Fantoni, anthony.perard, Gaowei (UVP),
	Huangweidong (Hardware)

>>> On 24.10.13 at 14:17, "Gonglei (Arei)" <arei.gonglei@huawei.com> wrote:
> Now I test the patch based on the codes of trunk, which works well.
> The patch has been modified after your suggestion.

Partly. I looks reasonable now, but still not pretty. But the tools
maintainers will have to have the final say here anyway.

Jan

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [Xen-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
  2013-10-28  9:38                   ` [Qemu-devel] [Xen-devel] " Jan Beulich
@ 2014-01-22 14:32                     ` Fabio Fantoni
  2014-04-28 10:14                       ` [Qemu-devel] " Fabio Fantoni
       [not found]                       ` <535E2A18.9040504@m2r.biz>
  2014-01-22 14:32                     ` Fabio Fantoni
  1 sibling, 2 replies; 38+ messages in thread
From: Fabio Fantoni @ 2014-01-22 14:32 UTC (permalink / raw)
  To: Jan Beulich, Gonglei (Arei)
  Cc: Yanqiangjun, Ian Campbell, Hanweidong (Randy),
	Markus Armbruster, Stefano Stabellini, Luonengjun, qemu-devel,
	xen-devel, anthony.perard, Gaowei (UVP), Huangweidong (Hardware)

Il 28/10/2013 10:38, Jan Beulich ha scritto:
>>>> On 24.10.13 at 14:17, "Gonglei (Arei)" <arei.gonglei@huawei.com> wrote:
>> Now I test the patch based on the codes of trunk, which works well.
>> The patch has been modified after your suggestion.
> Partly. I looks reasonable now, but still not pretty. But the tools
> maintainers will have to have the final say here anyway.
>
> Jan
>

Are there news about this patch?

Thanks for any reply.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
  2013-10-28  9:38                   ` [Qemu-devel] [Xen-devel] " Jan Beulich
  2014-01-22 14:32                     ` Fabio Fantoni
@ 2014-01-22 14:32                     ` Fabio Fantoni
  1 sibling, 0 replies; 38+ messages in thread
From: Fabio Fantoni @ 2014-01-22 14:32 UTC (permalink / raw)
  To: Jan Beulich, Gonglei (Arei)
  Cc: Yanqiangjun, Ian Campbell, Hanweidong (Randy),
	Markus Armbruster, Stefano Stabellini, Luonengjun, qemu-devel,
	xen-devel, anthony.perard, Gaowei (UVP), Huangweidong (Hardware)

Il 28/10/2013 10:38, Jan Beulich ha scritto:
>>>> On 24.10.13 at 14:17, "Gonglei (Arei)" <arei.gonglei@huawei.com> wrote:
>> Now I test the patch based on the codes of trunk, which works well.
>> The patch has been modified after your suggestion.
> Partly. I looks reasonable now, but still not pretty. But the tools
> maintainers will have to have the final say here anyway.
>
> Jan
>

Are there news about this patch?

Thanks for any reply.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
  2014-01-22 14:32                     ` Fabio Fantoni
@ 2014-04-28 10:14                       ` Fabio Fantoni
       [not found]                       ` <535E2A18.9040504@m2r.biz>
  1 sibling, 0 replies; 38+ messages in thread
From: Fabio Fantoni @ 2014-04-28 10:14 UTC (permalink / raw)
  To: Jan Beulich, Gonglei (Arei)
  Cc: Yanqiangjun, Ian Campbell, Hanweidong (Randy),
	Markus Armbruster, Stefano Stabellini, Luonengjun, qemu-devel,
	xen-devel, anthony.perard, Gaowei (UVP), Huangweidong (Hardware)

Il 22/01/2014 15:32, Fabio Fantoni ha scritto:
> Il 28/10/2013 10:38, Jan Beulich ha scritto:
>>>>> On 24.10.13 at 14:17, "Gonglei (Arei)" <arei.gonglei@huawei.com> 
>>>>> wrote:
>>> Now I test the patch based on the codes of trunk, which works well.
>>> The patch has been modified after your suggestion.
>> Partly. I looks reasonable now, but still not pretty. But the tools
>> maintainers will have to have the final say here anyway.
>>
>> Jan
>>
>
> Are there news about this patch?
>
> Thanks for any reply.
Ping

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
       [not found]                       ` <535E2A18.9040504@m2r.biz>
@ 2014-04-28 10:21                         ` Ian Campbell
       [not found]                         ` <1398680460.29700.34.camel@kazak.uk.xensource.com>
  1 sibling, 0 replies; 38+ messages in thread
From: Ian Campbell @ 2014-04-28 10:21 UTC (permalink / raw)
  To: Fabio Fantoni
  Cc: Yanqiangjun, Hanweidong (Randy),
	Markus Armbruster, Stefano Stabellini, Luonengjun, qemu-devel,
	xen-devel, Gonglei (Arei),
	Jan Beulich, anthony.perard, Gaowei (UVP),
	Huangweidong (Hardware)

On Mon, 2014-04-28 at 12:14 +0200, Fabio Fantoni wrote:
> Il 22/01/2014 15:32, Fabio Fantoni ha scritto:
> > Il 28/10/2013 10:38, Jan Beulich ha scritto:
> >>>>> On 24.10.13 at 14:17, "Gonglei (Arei)" <arei.gonglei@huawei.com> 
> >>>>> wrote:
> >>> Now I test the patch based on the codes of trunk, which works well.
> >>> The patch has been modified after your suggestion.
> >> Partly. I looks reasonable now, but still not pretty. But the tools
> >> maintainers will have to have the final say here anyway.
> >>
> >> Jan
> >>
> >
> > Are there news about this patch?
> >
> > Thanks for any reply.
> Ping

AFAICT the ball here is in the submitters court.

Ian.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
       [not found]                         ` <1398680460.29700.34.camel@kazak.uk.xensource.com>
@ 2014-04-28 12:04                           ` Gonglei (Arei)
       [not found]                           ` <33183CC9F5247A488A2544077AF19020815E325F@SZXEMA503-MBS.china.huawei.com>
  1 sibling, 0 replies; 38+ messages in thread
From: Gonglei (Arei) @ 2014-04-28 12:04 UTC (permalink / raw)
  To: Ian Campbell, Fabio Fantoni
  Cc: Yanqiangjun, Hanweidong (Randy),
	Markus Armbruster, Stefano Stabellini, Luonengjun, qemu-devel,
	xen-devel, Jan Beulich, anthony.perard, Gaowei (UVP),
	Huangweidong (Agisson)

Hi,

> Subject: Re: [Qemu-devel] [Xen-devel] Hvmloader: Modify ACPI to only supply
> _EJ0 methods for PCIslots that support hotplug by runtime patching
> 
> On Mon, 2014-04-28 at 12:14 +0200, Fabio Fantoni wrote:
> > Il 22/01/2014 15:32, Fabio Fantoni ha scritto:
> > > Il 28/10/2013 10:38, Jan Beulich ha scritto:
> > >>>>> On 24.10.13 at 14:17, "Gonglei (Arei)" <arei.gonglei@huawei.com>
> > >>>>> wrote:
> > >>> Now I test the patch based on the codes of trunk, which works well.
> > >>> The patch has been modified after your suggestion.
> > >> Partly. I looks reasonable now, but still not pretty. But the tools
> > >> maintainers will have to have the final say here anyway.
> > >>
> > >> Jan
> > >>
> > >
> > > Are there news about this patch?
> > >
> > > Thanks for any reply.
> > Ping
> 
> AFAICT the ball here is in the submitters court.
> 
> Ian.
> 
It's so long time now, and I go near to forget this patch. 
Because my work is now mainly on KVM. But the patch is 
really usefully for XEN.


Best regards,
-Gonglei

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
       [not found]                           ` <33183CC9F5247A488A2544077AF19020815E325F@SZXEMA503-MBS.china.huawei.com>
@ 2014-04-28 13:58                             ` Fabio Fantoni
       [not found]                             ` <535E5E82.40102@m2r.biz>
  1 sibling, 0 replies; 38+ messages in thread
From: Fabio Fantoni @ 2014-04-28 13:58 UTC (permalink / raw)
  To: Gonglei (Arei), Ian Campbell
  Cc: Yanqiangjun, Hanweidong (Randy),
	Markus Armbruster, Stefano Stabellini, Luonengjun, qemu-devel,
	xen-devel, Jan Beulich, anthony.perard, Gaowei (UVP),
	Huangweidong (Agisson)

Il 28/04/2014 14:04, Gonglei (Arei) ha scritto:
> Hi,
>
>> Subject: Re: [Qemu-devel] [Xen-devel] Hvmloader: Modify ACPI to only supply
>> _EJ0 methods for PCIslots that support hotplug by runtime patching
>>
>> On Mon, 2014-04-28 at 12:14 +0200, Fabio Fantoni wrote:
>>> Il 22/01/2014 15:32, Fabio Fantoni ha scritto:
>>>> Il 28/10/2013 10:38, Jan Beulich ha scritto:
>>>>>>>> On 24.10.13 at 14:17, "Gonglei (Arei)" <arei.gonglei@huawei.com>
>>>>>>>> wrote:
>>>>>> Now I test the patch based on the codes of trunk, which works well.
>>>>>> The patch has been modified after your suggestion.
>>>>> Partly. I looks reasonable now, but still not pretty. But the tools
>>>>> maintainers will have to have the final say here anyway.
>>>>>
>>>>> Jan
>>>>>
>>>> Are there news about this patch?
>>>>
>>>> Thanks for any reply.
>>> Ping
>> AFAICT the ball here is in the submitters court.
>>
>> Ian.
>>
> It's so long time now, and I go near to forget this patch.
> Because my work is now mainly on KVM. But the patch is
> really usefully for XEN.
>
>
> Best regards,
> -Gonglei

Could you repost it for xen 4.5?

Thanks for any reply.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching
       [not found]                             ` <535E5E82.40102@m2r.biz>
@ 2014-04-29  3:27                               ` Gonglei (Arei)
  0 siblings, 0 replies; 38+ messages in thread
From: Gonglei (Arei) @ 2014-04-29  3:27 UTC (permalink / raw)
  To: Fabio Fantoni, Ian Campbell
  Cc: Yanqiangjun, Hanweidong (Randy),
	Markus Armbruster, Stefano Stabellini, Luonengjun, qemu-devel,
	xen-devel, Jan Beulich, anthony.perard, Gaowei (UVP),
	Huangweidong (Agisson)

Hi,

> >> Subject: Re: [Qemu-devel] [Xen-devel] Hvmloader: Modify ACPI to only
> supply
> >> _EJ0 methods for PCIslots that support hotplug by runtime patching
> >>
> >> On Mon, 2014-04-28 at 12:14 +0200, Fabio Fantoni wrote:
> >>> Il 22/01/2014 15:32, Fabio Fantoni ha scritto:
> >>>> Il 28/10/2013 10:38, Jan Beulich ha scritto:
> >>>>>>>> On 24.10.13 at 14:17, "Gonglei (Arei)" <arei.gonglei@huawei.com>
> >>>>>>>> wrote:
> >>>>>> Now I test the patch based on the codes of trunk, which works well.
> >>>>>> The patch has been modified after your suggestion.
> >>>>> Partly. I looks reasonable now, but still not pretty. But the tools
> >>>>> maintainers will have to have the final say here anyway.
> >>>>>
> >>>>> Jan
> >>>>>
> >>>> Are there news about this patch?
> >>>>
> >>>> Thanks for any reply.
> >>> Ping
> >> AFAICT the ball here is in the submitters court.
> >>
> >> Ian.
> >>
> > It's so long time now, and I go near to forget this patch.
> > Because my work is now mainly on KVM. But the patch is
> > really usefully for XEN.
> >
> >
> > Best regards,
> > -Gonglei
> 
> Could you repost it for xen 4.5?
> 
> Thanks for any reply.

Okay, I will do that in the next several days. 
Thank you for reminding.

Best regards,
-Gonglei

^ permalink raw reply	[flat|nested] 38+ messages in thread

end of thread, other threads:[~2014-04-29  3:27 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-10-16  6:30 [Qemu-devel] Hvmloader: Modify ACPI to only supply _EJ0 methods for PCIslots that support hotplug by runtime patching Gonglei (Arei)
2013-10-16  9:13 ` Fabio Fantoni
2013-10-16  9:13 ` [Qemu-devel] " Fabio Fantoni
2013-10-16  9:19 ` Ian Campbell
2013-10-16  9:19 ` [Qemu-devel] [Xen-devel] " Ian Campbell
2013-10-16  9:54 ` Jan Beulich
2013-10-16 10:04   ` Ian Campbell
2013-10-16 10:49     ` Markus Armbruster
2013-10-16 10:58       ` Ian Campbell
2013-10-16 11:10         ` Markus Armbruster
2013-10-16 12:03           ` Jan Beulich
2013-10-22  4:08             ` Gonglei (Arei)
2013-10-22  8:06               ` [Qemu-devel] " Jan Beulich
2013-10-22  8:06               ` [Qemu-devel] [Xen-devel] " Jan Beulich
2013-10-24 12:17                 ` [Qemu-devel] " Gonglei (Arei)
2013-10-24 12:17                 ` [Qemu-devel] [Xen-devel] " Gonglei (Arei)
2013-10-24 12:57                   ` Fabio Fantoni
2013-10-24 13:16                     ` [Qemu-devel] " Gonglei (Arei)
2013-10-24 13:16                     ` [Qemu-devel] [Xen-devel] " Gonglei (Arei)
2013-10-24 12:57                   ` [Qemu-devel] " Fabio Fantoni
2013-10-28  9:38                   ` Jan Beulich
2013-10-28  9:38                   ` [Qemu-devel] [Xen-devel] " Jan Beulich
2014-01-22 14:32                     ` Fabio Fantoni
2014-04-28 10:14                       ` [Qemu-devel] " Fabio Fantoni
     [not found]                       ` <535E2A18.9040504@m2r.biz>
2014-04-28 10:21                         ` Ian Campbell
     [not found]                         ` <1398680460.29700.34.camel@kazak.uk.xensource.com>
2014-04-28 12:04                           ` Gonglei (Arei)
     [not found]                           ` <33183CC9F5247A488A2544077AF19020815E325F@SZXEMA503-MBS.china.huawei.com>
2014-04-28 13:58                             ` Fabio Fantoni
     [not found]                             ` <535E5E82.40102@m2r.biz>
2014-04-29  3:27                               ` Gonglei (Arei)
2014-01-22 14:32                     ` Fabio Fantoni
2013-10-28  7:14                 ` Gonglei (Arei)
2013-10-28  7:14                 ` [Qemu-devel] [Xen-devel] " Gonglei (Arei)
2013-10-22  4:08             ` [Qemu-devel] " Gonglei (Arei)
2013-10-16 12:03           ` Jan Beulich
2013-10-16 11:10         ` Markus Armbruster
2013-10-16 10:58       ` Ian Campbell
2013-10-16 10:49     ` Markus Armbruster
2013-10-16 10:04   ` Ian Campbell
2013-10-16  9:54 ` Jan Beulich

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.