diff mbox

[v7,25/35] nvdimm acpi: init the resource used by NVDIMM ACPI

Message ID 1446455617-129562-26-git-send-email-guangrong.xiao@linux.intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Xiao Guangrong Nov. 2, 2015, 9:13 a.m. UTC
A page staring from 0xFF00000 and IO port 0x0a18 - 0xa1b in guest are
reserved for NVDIMM ACPI emulation, refer to docs/specs/acpi_nvdimm.txt
for detailed design

A parameter, 'nvdimm-support', is introduced for PIIX4_PM and ICH9-LPC
that controls if nvdimm support is enabled, it is true on default and
it is false on 2.4 and its earlier version to keep compatibility

Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com>
---
 default-configs/i386-softmmu.mak     |  1 +
 default-configs/mips-softmmu.mak     |  1 +
 default-configs/mips64-softmmu.mak   |  1 +
 default-configs/mips64el-softmmu.mak |  1 +
 default-configs/mipsel-softmmu.mak   |  1 +
 default-configs/x86_64-softmmu.mak   |  1 +
 hw/acpi/Makefile.objs                |  1 +
 hw/acpi/ich9.c                       | 24 ++++++++++++++
 hw/acpi/nvdimm.c                     | 63 ++++++++++++++++++++++++++++++++++++
 hw/acpi/piix4.c                      | 27 ++++++++++++----
 include/hw/acpi/ich9.h               |  3 ++
 include/hw/i386/pc.h                 | 10 ++++++
 include/hw/mem/nvdimm.h              | 34 +++++++++++++++++++
 13 files changed, 161 insertions(+), 7 deletions(-)
 create mode 100644 hw/acpi/nvdimm.c

Comments

Igor Mammedov Nov. 5, 2015, 9:58 a.m. UTC | #1
On Mon,  2 Nov 2015 17:13:27 +0800
Xiao Guangrong <guangrong.xiao@linux.intel.com> wrote:

> A page staring from 0xFF00000 and IO port 0x0a18 - 0xa1b in guest are
                               ^^ missing one 0???

> reserved for NVDIMM ACPI emulation, refer to docs/specs/acpi_nvdimm.txt
> for detailed design
> 
> A parameter, 'nvdimm-support', is introduced for PIIX4_PM and ICH9-LPC
> that controls if nvdimm support is enabled, it is true on default and
> it is false on 2.4 and its earlier version to keep compatibility
> 
> Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com>
[...]

> @@ -33,6 +33,15 @@
>   */
>  #define MIN_NAMESPACE_LABEL_SIZE      (128UL << 10)
>  
> +/*
> + * A page staring from 0xFF00000 and IO port 0x0a18 - 0xa1b in guest are
                                 ^^^ missing 0 or value in define below has an extra 0

> + * reserved for NVDIMM ACPI emulation, refer to docs/specs/acpi_nvdimm.txt
> + * for detailed design.
> + */
> +#define NVDIMM_ACPI_MEM_BASE          0xFF000000ULL
it still maps RAM at arbitrary place,
that's the reason why VMGenID patches hasn't been merged for
more than several months.
I'm not against of using (more exactly I'm for it) direct mapping
but we should reach consensus when and how to use it first.

I'd wouldn't use addresses below 4G as it may be used firmware or
legacy hardware and I won't bet that 0xFF000000ULL won't conflict
with anything.
An alternative place to allocate reserve from could be high memory.
For pc we have "reserved-memory-end" which currently makes sure
that hotpluggable memory range isn't used by firmware.

How about making API that allows to map additional memory
ranges before reserved-memory-end and pushes it up as mappings are
added.

Michael, Paolo what do you think about it?


> +#define NVDIMM_ACPI_IO_BASE           0x0a18
> +#define NVDIMM_ACPI_IO_LEN            4
> +
>  #define TYPE_NVDIMM      "nvdimm"
>  #define NVDIMM(obj)      OBJECT_CHECK(NVDIMMDevice, (obj), TYPE_NVDIMM)
>  #define NVDIMM_CLASS(oc) OBJECT_CLASS_CHECK(NVDIMMClass, (oc), TYPE_NVDIMM)
> @@ -80,4 +89,29 @@ struct NVDIMMClass {
>  };
>  typedef struct NVDIMMClass NVDIMMClass;
>  
> +/*
> + * AcpiNVDIMMState:
> + * @is_enabled: detect if NVDIMM support is enabled.
> + *
> + * @fit: fit buffer which will be accessed via ACPI _FIT method. It is
> + *       dynamically built based on current NVDIMM devices so that it does
> + *       not require to keep consistent during live migration.
> + *
> + * @ram_mr: RAM-based memory region which is mapped into guest address
> + *          space and used to transfer data between OSPM and QEMU.
> + * @io_mr: the IO region used by OSPM to transfer control to QEMU.
> + */
> +struct AcpiNVDIMMState {
> +    bool is_enabled;
> +
> +    GArray *fit;
> +
> +    MemoryRegion ram_mr;
> +    MemoryRegion io_mr;
> +};
> +typedef struct AcpiNVDIMMState AcpiNVDIMMState;
> +
> +/* Initialize the memory and IO region needed by NVDIMM ACPI emulation.*/
> +void nvdimm_init_acpi_state(MemoryRegion *memory, MemoryRegion *io,
> +                            Object *owner, AcpiNVDIMMState *state);
>  #endif

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Xiao Guangrong Nov. 5, 2015, 10:15 a.m. UTC | #2
On 11/05/2015 05:58 PM, Igor Mammedov wrote:
> On Mon,  2 Nov 2015 17:13:27 +0800
> Xiao Guangrong <guangrong.xiao@linux.intel.com> wrote:
>
>> A page staring from 0xFF00000 and IO port 0x0a18 - 0xa1b in guest are
>                                 ^^ missing one 0???
>
>> reserved for NVDIMM ACPI emulation, refer to docs/specs/acpi_nvdimm.txt
>> for detailed design
>>
>> A parameter, 'nvdimm-support', is introduced for PIIX4_PM and ICH9-LPC
>> that controls if nvdimm support is enabled, it is true on default and
>> it is false on 2.4 and its earlier version to keep compatibility
>>
>> Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com>
> [...]
>
>> @@ -33,6 +33,15 @@
>>    */
>>   #define MIN_NAMESPACE_LABEL_SIZE      (128UL << 10)
>>
>> +/*
>> + * A page staring from 0xFF00000 and IO port 0x0a18 - 0xa1b in guest are
>                                   ^^^ missing 0 or value in define below has an extra 0
>
>> + * reserved for NVDIMM ACPI emulation, refer to docs/specs/acpi_nvdimm.txt
>> + * for detailed design.
>> + */
>> +#define NVDIMM_ACPI_MEM_BASE          0xFF000000ULL
> it still maps RAM at arbitrary place,
> that's the reason why VMGenID patches hasn't been merged for
> more than several months.
> I'm not against of using (more exactly I'm for it) direct mapping
> but we should reach consensus when and how to use it first.
>
> I'd wouldn't use addresses below 4G as it may be used firmware or
> legacy hardware and I won't bet that 0xFF000000ULL won't conflict
> with anything.
> An alternative place to allocate reserve from could be high memory.
> For pc we have "reserved-memory-end" which currently makes sure
> that hotpluggable memory range isn't used by firmware.
>
> How about making API that allows to map additional memory
> ranges before reserved-memory-end and pushes it up as mappings are
> added.

That what i did in the v1/v2 versions, however, as you noticed, using 64-bit
address in ACPI in QEMU is not a easy work - we can not simply make
SSDT.rev = 2 to apply 64 bit address, the reason i have documented in
v3's changelog:

   3) we figure out a unused memory hole below 4G that is 0xFF00000 ~
      0xFFF00000, this range is large enough for NVDIMM ACPI as build 64-bit
      ACPI SSDT/DSDT table will break windows XP.
      BTW, only make SSDT.rev = 2 can not work since the width is only depended
      on DSDT.rev based on 19.6.28 DefinitionBlock (Declare Definition Block)
      in ACPI spec:
| Note: For compatibility with ACPI versions before ACPI 2.0, the bit
| width of Integer objects is dependent on the ComplianceRevision of the DSDT.
| If the ComplianceRevision is less than 2, all integers are restricted to 32
| bits. Otherwise, full 64-bit integers are used. The version of the DSDT sets
| the global integer width for all integers, including integers in SSDTs.
   4) use the lowest ACPI spec version to document AML terms.

The only way introducing 64 bit address is adding XSDT support that what
Michael did before, however, it seems it need great efforts to do it as
it will break OVMF. It's a long term workload. :(

The luck thing is, the ACPI part is not ABI, we can move it to the high
memory if QEMU supports XSDT is ready in future development.

Thanks!
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Igor Mammedov Nov. 5, 2015, 1:03 p.m. UTC | #3
On Thu, 5 Nov 2015 18:15:31 +0800
Xiao Guangrong <guangrong.xiao@linux.intel.com> wrote:

> 
> 
> On 11/05/2015 05:58 PM, Igor Mammedov wrote:
> > On Mon,  2 Nov 2015 17:13:27 +0800
> > Xiao Guangrong <guangrong.xiao@linux.intel.com> wrote:
> >
> >> A page staring from 0xFF00000 and IO port 0x0a18 - 0xa1b in guest are
> >                                 ^^ missing one 0???
> >
> >> reserved for NVDIMM ACPI emulation, refer to docs/specs/acpi_nvdimm.txt
> >> for detailed design
> >>
> >> A parameter, 'nvdimm-support', is introduced for PIIX4_PM and ICH9-LPC
> >> that controls if nvdimm support is enabled, it is true on default and
> >> it is false on 2.4 and its earlier version to keep compatibility
> >>
> >> Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com>
> > [...]
> >
> >> @@ -33,6 +33,15 @@
> >>    */
> >>   #define MIN_NAMESPACE_LABEL_SIZE      (128UL << 10)
> >>
> >> +/*
> >> + * A page staring from 0xFF00000 and IO port 0x0a18 - 0xa1b in guest are
> >                                   ^^^ missing 0 or value in define below has an extra 0
> >
> >> + * reserved for NVDIMM ACPI emulation, refer to docs/specs/acpi_nvdimm.txt
> >> + * for detailed design.
> >> + */
> >> +#define NVDIMM_ACPI_MEM_BASE          0xFF000000ULL
> > it still maps RAM at arbitrary place,
> > that's the reason why VMGenID patches hasn't been merged for
> > more than several months.
> > I'm not against of using (more exactly I'm for it) direct mapping
> > but we should reach consensus when and how to use it first.
> >
> > I'd wouldn't use addresses below 4G as it may be used firmware or
> > legacy hardware and I won't bet that 0xFF000000ULL won't conflict
> > with anything.
> > An alternative place to allocate reserve from could be high memory.
> > For pc we have "reserved-memory-end" which currently makes sure
> > that hotpluggable memory range isn't used by firmware.
> >
> > How about making API that allows to map additional memory
> > ranges before reserved-memory-end and pushes it up as mappings are
> > added.
> 
> That what i did in the v1/v2 versions, however, as you noticed, using 64-bit
> address in ACPI in QEMU is not a easy work - we can not simply make
> SSDT.rev = 2 to apply 64 bit address, the reason i have documented in
> v3's changelog:
> 
>    3) we figure out a unused memory hole below 4G that is 0xFF00000 ~
>       0xFFF00000, this range is large enough for NVDIMM ACPI as build 64-bit
>       ACPI SSDT/DSDT table will break windows XP.
>       BTW, only make SSDT.rev = 2 can not work since the width is only depended
>       on DSDT.rev based on 19.6.28 DefinitionBlock (Declare Definition Block)
>       in ACPI spec:
> | Note: For compatibility with ACPI versions before ACPI 2.0, the bit
> | width of Integer objects is dependent on the ComplianceRevision of the DSDT.
> | If the ComplianceRevision is less than 2, all integers are restricted to 32
> | bits. Otherwise, full 64-bit integers are used. The version of the DSDT sets
> | the global integer width for all integers, including integers in SSDTs.
>    4) use the lowest ACPI spec version to document AML terms.
> 
> The only way introducing 64 bit address is adding XSDT support that what
> Michael did before, however, it seems it need great efforts to do it as
> it will break OVMF. It's a long term workload. :(
to enable 64-bit integers in AML it's sufficient to change DSDT revision to 2,
I already have a patch that switches DSDT/SSDT to rev2.
Tests show it doesn't break WindowsXP (which is rev1) and uses 64-bit integers
on linux & later Windows versions.

> 
> The luck thing is, the ACPI part is not ABI, we can move it to the high
> memory if QEMU supports XSDT is ready in future development.
But mapped control region is ABI and we can't change it if we find out later
that it breaks something.

> 
> Thanks!

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Xiao Guangrong Nov. 5, 2015, 1:33 p.m. UTC | #4
On 11/05/2015 09:03 PM, Igor Mammedov wrote:
> On Thu, 5 Nov 2015 18:15:31 +0800
> Xiao Guangrong <guangrong.xiao@linux.intel.com> wrote:
>
>>
>>
>> On 11/05/2015 05:58 PM, Igor Mammedov wrote:
>>> On Mon,  2 Nov 2015 17:13:27 +0800
>>> Xiao Guangrong <guangrong.xiao@linux.intel.com> wrote:
>>>
>>>> A page staring from 0xFF00000 and IO port 0x0a18 - 0xa1b in guest are
>>>                                  ^^ missing one 0???
>>>
>>>> reserved for NVDIMM ACPI emulation, refer to docs/specs/acpi_nvdimm.txt
>>>> for detailed design
>>>>
>>>> A parameter, 'nvdimm-support', is introduced for PIIX4_PM and ICH9-LPC
>>>> that controls if nvdimm support is enabled, it is true on default and
>>>> it is false on 2.4 and its earlier version to keep compatibility
>>>>
>>>> Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com>
>>> [...]
>>>
>>>> @@ -33,6 +33,15 @@
>>>>     */
>>>>    #define MIN_NAMESPACE_LABEL_SIZE      (128UL << 10)
>>>>
>>>> +/*
>>>> + * A page staring from 0xFF00000 and IO port 0x0a18 - 0xa1b in guest are
>>>                                    ^^^ missing 0 or value in define below has an extra 0
>>>
>>>> + * reserved for NVDIMM ACPI emulation, refer to docs/specs/acpi_nvdimm.txt
>>>> + * for detailed design.
>>>> + */
>>>> +#define NVDIMM_ACPI_MEM_BASE          0xFF000000ULL
>>> it still maps RAM at arbitrary place,
>>> that's the reason why VMGenID patches hasn't been merged for
>>> more than several months.
>>> I'm not against of using (more exactly I'm for it) direct mapping
>>> but we should reach consensus when and how to use it first.
>>>
>>> I'd wouldn't use addresses below 4G as it may be used firmware or
>>> legacy hardware and I won't bet that 0xFF000000ULL won't conflict
>>> with anything.
>>> An alternative place to allocate reserve from could be high memory.
>>> For pc we have "reserved-memory-end" which currently makes sure
>>> that hotpluggable memory range isn't used by firmware.
>>>
>>> How about making API that allows to map additional memory
>>> ranges before reserved-memory-end and pushes it up as mappings are
>>> added.
>>
>> That what i did in the v1/v2 versions, however, as you noticed, using 64-bit
>> address in ACPI in QEMU is not a easy work - we can not simply make
>> SSDT.rev = 2 to apply 64 bit address, the reason i have documented in
>> v3's changelog:
>>
>>     3) we figure out a unused memory hole below 4G that is 0xFF00000 ~
>>        0xFFF00000, this range is large enough for NVDIMM ACPI as build 64-bit
>>        ACPI SSDT/DSDT table will break windows XP.
>>        BTW, only make SSDT.rev = 2 can not work since the width is only depended
>>        on DSDT.rev based on 19.6.28 DefinitionBlock (Declare Definition Block)
>>        in ACPI spec:
>> | Note: For compatibility with ACPI versions before ACPI 2.0, the bit
>> | width of Integer objects is dependent on the ComplianceRevision of the DSDT.
>> | If the ComplianceRevision is less than 2, all integers are restricted to 32
>> | bits. Otherwise, full 64-bit integers are used. The version of the DSDT sets
>> | the global integer width for all integers, including integers in SSDTs.
>>     4) use the lowest ACPI spec version to document AML terms.
>>
>> The only way introducing 64 bit address is adding XSDT support that what
>> Michael did before, however, it seems it need great efforts to do it as
>> it will break OVMF. It's a long term workload. :(
> to enable 64-bit integers in AML it's sufficient to change DSDT revision to 2,
> I already have a patch that switches DSDT/SSDT to rev2.
> Tests show it doesn't break WindowsXP (which is rev1) and uses 64-bit integers
> on linux & later Windows versions.

Great, i remembered i did the similar test (directly change DSDT to rev2) and it
caused winXP blue screen. Could you please tell me where i can find your patch?

>
>>
>> The luck thing is, the ACPI part is not ABI, we can move it to the high
>> memory if QEMU supports XSDT is ready in future development.
> But mapped control region is ABI and we can't change it if we find out later
> that it breaks something.

But the ACPI code is completely built by QEMU, which is transparent to guest
and guest should not depend on it, no?

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Igor Mammedov Nov. 5, 2015, 2:49 p.m. UTC | #5
On Thu, 5 Nov 2015 21:33:39 +0800
Xiao Guangrong <guangrong.xiao@linux.intel.com> wrote:

> 
> 
> On 11/05/2015 09:03 PM, Igor Mammedov wrote:
> > On Thu, 5 Nov 2015 18:15:31 +0800
> > Xiao Guangrong <guangrong.xiao@linux.intel.com> wrote:
> >
> >>
> >>
> >> On 11/05/2015 05:58 PM, Igor Mammedov wrote:
> >>> On Mon,  2 Nov 2015 17:13:27 +0800
> >>> Xiao Guangrong <guangrong.xiao@linux.intel.com> wrote:
> >>>
> >>>> A page staring from 0xFF00000 and IO port 0x0a18 - 0xa1b in guest are
> >>>                                  ^^ missing one 0???
> >>>
> >>>> reserved for NVDIMM ACPI emulation, refer to docs/specs/acpi_nvdimm.txt
> >>>> for detailed design
> >>>>
> >>>> A parameter, 'nvdimm-support', is introduced for PIIX4_PM and ICH9-LPC
> >>>> that controls if nvdimm support is enabled, it is true on default and
> >>>> it is false on 2.4 and its earlier version to keep compatibility
> >>>>
> >>>> Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com>
> >>> [...]
> >>>
> >>>> @@ -33,6 +33,15 @@
> >>>>     */
> >>>>    #define MIN_NAMESPACE_LABEL_SIZE      (128UL << 10)
> >>>>
> >>>> +/*
> >>>> + * A page staring from 0xFF00000 and IO port 0x0a18 - 0xa1b in guest are
> >>>                                    ^^^ missing 0 or value in define below has an extra 0
> >>>
> >>>> + * reserved for NVDIMM ACPI emulation, refer to docs/specs/acpi_nvdimm.txt
> >>>> + * for detailed design.
> >>>> + */
> >>>> +#define NVDIMM_ACPI_MEM_BASE          0xFF000000ULL
> >>> it still maps RAM at arbitrary place,
> >>> that's the reason why VMGenID patches hasn't been merged for
> >>> more than several months.
> >>> I'm not against of using (more exactly I'm for it) direct mapping
> >>> but we should reach consensus when and how to use it first.
> >>>
> >>> I'd wouldn't use addresses below 4G as it may be used firmware or
> >>> legacy hardware and I won't bet that 0xFF000000ULL won't conflict
> >>> with anything.
> >>> An alternative place to allocate reserve from could be high memory.
> >>> For pc we have "reserved-memory-end" which currently makes sure
> >>> that hotpluggable memory range isn't used by firmware.
> >>>
> >>> How about making API that allows to map additional memory
> >>> ranges before reserved-memory-end and pushes it up as mappings are
> >>> added.
> >>
> >> That what i did in the v1/v2 versions, however, as you noticed, using 64-bit
> >> address in ACPI in QEMU is not a easy work - we can not simply make
> >> SSDT.rev = 2 to apply 64 bit address, the reason i have documented in
> >> v3's changelog:
> >>
> >>     3) we figure out a unused memory hole below 4G that is 0xFF00000 ~
> >>        0xFFF00000, this range is large enough for NVDIMM ACPI as build 64-bit
> >>        ACPI SSDT/DSDT table will break windows XP.
> >>        BTW, only make SSDT.rev = 2 can not work since the width is only depended
> >>        on DSDT.rev based on 19.6.28 DefinitionBlock (Declare Definition Block)
> >>        in ACPI spec:
> >> | Note: For compatibility with ACPI versions before ACPI 2.0, the bit
> >> | width of Integer objects is dependent on the ComplianceRevision of the DSDT.
> >> | If the ComplianceRevision is less than 2, all integers are restricted to 32
> >> | bits. Otherwise, full 64-bit integers are used. The version of the DSDT sets
> >> | the global integer width for all integers, including integers in SSDTs.
> >>     4) use the lowest ACPI spec version to document AML terms.
> >>
> >> The only way introducing 64 bit address is adding XSDT support that what
> >> Michael did before, however, it seems it need great efforts to do it as
> >> it will break OVMF. It's a long term workload. :(
> > to enable 64-bit integers in AML it's sufficient to change DSDT revision to 2,
> > I already have a patch that switches DSDT/SSDT to rev2.
> > Tests show it doesn't break WindowsXP (which is rev1) and uses 64-bit integers
> > on linux & later Windows versions.
> 
> Great, i remembered i did the similar test (directly change DSDT to rev2) and it
> caused winXP blue screen. Could you please tell me where i can find your patch?
https://github.com/imammedo/qemu/commits/mhpt_table_v2
following changes revision:
 pc: acpi: bump DSDT/SSDT compliance revision to v2
and here is user:
 acpi: memhp: simplify MCRS() using 64-bit math

when writing ASL one shall make sure that only XP supported
features are in global scope, which is evaluated when tables
are loaded and features of rev2 and higher are inside methods.
That way XP doesn't crash as far as it doesn't evaluate unsupported
opcode and one can guard those opcodes checking _REV object if neccesary.


> >>
> >> The luck thing is, the ACPI part is not ABI, we can move it to the high
> >> memory if QEMU supports XSDT is ready in future development.
> > But mapped control region is ABI and we can't change it if we find out later
> > that it breaks something.
> 
> But the ACPI code is completely built by QEMU, which is transparent to guest
> and guest should not depend on it, no?
unfortunately no, think about cross-version migration.

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
index 4e84a1c..51e71d4 100644
--- a/default-configs/i386-softmmu.mak
+++ b/default-configs/i386-softmmu.mak
@@ -48,6 +48,7 @@  CONFIG_IOAPIC=y
 CONFIG_PVPANIC=y
 CONFIG_MEM_HOTPLUG=y
 CONFIG_NVDIMM=y
+CONFIG_ACPI_NVDIMM=y
 CONFIG_XIO3130=y
 CONFIG_IOH3420=y
 CONFIG_I82801B11=y
diff --git a/default-configs/mips-softmmu.mak b/default-configs/mips-softmmu.mak
index 44467c3..6b8b70e 100644
--- a/default-configs/mips-softmmu.mak
+++ b/default-configs/mips-softmmu.mak
@@ -17,6 +17,7 @@  CONFIG_FDC=y
 CONFIG_ACPI=y
 CONFIG_ACPI_X86=y
 CONFIG_ACPI_MEMORY_HOTPLUG=y
+CONFIG_ACPI_NVDIMM=y
 CONFIG_ACPI_CPU_HOTPLUG=y
 CONFIG_APM=y
 CONFIG_I8257=y
diff --git a/default-configs/mips64-softmmu.mak b/default-configs/mips64-softmmu.mak
index 66ed5f9..ea820f6 100644
--- a/default-configs/mips64-softmmu.mak
+++ b/default-configs/mips64-softmmu.mak
@@ -17,6 +17,7 @@  CONFIG_FDC=y
 CONFIG_ACPI=y
 CONFIG_ACPI_X86=y
 CONFIG_ACPI_MEMORY_HOTPLUG=y
+CONFIG_ACPI_NVDIMM=y
 CONFIG_ACPI_CPU_HOTPLUG=y
 CONFIG_APM=y
 CONFIG_I8257=y
diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
index bfca2b2..8993851 100644
--- a/default-configs/mips64el-softmmu.mak
+++ b/default-configs/mips64el-softmmu.mak
@@ -17,6 +17,7 @@  CONFIG_FDC=y
 CONFIG_ACPI=y
 CONFIG_ACPI_X86=y
 CONFIG_ACPI_MEMORY_HOTPLUG=y
+CONFIG_ACPI_NVDIMM=y
 CONFIG_ACPI_CPU_HOTPLUG=y
 CONFIG_APM=y
 CONFIG_I8257=y
diff --git a/default-configs/mipsel-softmmu.mak b/default-configs/mipsel-softmmu.mak
index 0162ef0..87ab964 100644
--- a/default-configs/mipsel-softmmu.mak
+++ b/default-configs/mipsel-softmmu.mak
@@ -17,6 +17,7 @@  CONFIG_FDC=y
 CONFIG_ACPI=y
 CONFIG_ACPI_X86=y
 CONFIG_ACPI_MEMORY_HOTPLUG=y
+CONFIG_ACPI_NVDIMM=y
 CONFIG_ACPI_CPU_HOTPLUG=y
 CONFIG_APM=y
 CONFIG_I8257=y
diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak
index e877a86..0a7dc10 100644
--- a/default-configs/x86_64-softmmu.mak
+++ b/default-configs/x86_64-softmmu.mak
@@ -48,6 +48,7 @@  CONFIG_IOAPIC=y
 CONFIG_PVPANIC=y
 CONFIG_MEM_HOTPLUG=y
 CONFIG_NVDIMM=y
+CONFIG_ACPI_NVDIMM=y
 CONFIG_XIO3130=y
 CONFIG_IOH3420=y
 CONFIG_I82801B11=y
diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs
index 7d3230c..84c082d 100644
--- a/hw/acpi/Makefile.objs
+++ b/hw/acpi/Makefile.objs
@@ -2,6 +2,7 @@  common-obj-$(CONFIG_ACPI_X86) += core.o piix4.o pcihp.o
 common-obj-$(CONFIG_ACPI_X86_ICH) += ich9.o tco.o
 common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu_hotplug.o
 common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o
+obj-$(CONFIG_ACPI_NVDIMM) += nvdimm.o
 common-obj-$(CONFIG_ACPI) += acpi_interface.o
 common-obj-$(CONFIG_ACPI) += bios-linker-loader.o
 common-obj-$(CONFIG_ACPI) += aml-build.o
diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c
index 1e9ae20..603c1bd 100644
--- a/hw/acpi/ich9.c
+++ b/hw/acpi/ich9.c
@@ -280,6 +280,12 @@  void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm,
         acpi_memory_hotplug_init(pci_address_space_io(lpc_pci), OBJECT(lpc_pci),
                                  &pm->acpi_memory_hotplug);
     }
+
+    if (pm->acpi_nvdimm_state.is_enabled) {
+        nvdimm_init_acpi_state(pci_address_space(lpc_pci),
+                               pci_address_space_io(lpc_pci), OBJECT(lpc_pci),
+                               &pm->acpi_nvdimm_state);
+    }
 }
 
 static void ich9_pm_get_gpe0_blk(Object *obj, Visitor *v,
@@ -307,6 +313,20 @@  static void ich9_pm_set_memory_hotplug_support(Object *obj, bool value,
     s->pm.acpi_memory_hotplug.is_enabled = value;
 }
 
+static bool ich9_pm_get_nvdimm_support(Object *obj, Error **errp)
+{
+    ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
+
+    return s->pm.acpi_nvdimm_state.is_enabled;
+}
+
+static void ich9_pm_set_nvdimm_support(Object *obj, bool value, Error **errp)
+{
+    ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
+
+    s->pm.acpi_nvdimm_state.is_enabled = value;
+}
+
 static void ich9_pm_get_disable_s3(Object *obj, Visitor *v,
                                    void *opaque, const char *name,
                                    Error **errp)
@@ -419,6 +439,10 @@  void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm, Error **errp)
                              ich9_pm_get_memory_hotplug_support,
                              ich9_pm_set_memory_hotplug_support,
                              NULL);
+    object_property_add_bool(obj, "nvdimm-support",
+                             ich9_pm_get_nvdimm_support,
+                             ich9_pm_set_nvdimm_support,
+                             NULL);
     object_property_add(obj, ACPI_PM_PROP_S3_DISABLED, "uint8",
                         ich9_pm_get_disable_s3,
                         ich9_pm_set_disable_s3,
diff --git a/hw/acpi/nvdimm.c b/hw/acpi/nvdimm.c
new file mode 100644
index 0000000..1223da2
--- /dev/null
+++ b/hw/acpi/nvdimm.c
@@ -0,0 +1,63 @@ 
+/*
+ * NVDIMM ACPI Implementation
+ *
+ * Copyright(C) 2015 Intel Corporation.
+ *
+ * Author:
+ *  Xiao Guangrong <guangrong.xiao@linux.intel.com>
+ *
+ * NFIT is defined in ACPI 6.0: 5.2.25 NVDIMM Firmware Interface Table (NFIT)
+ * and the DSM specification can be found at:
+ *       http://pmem.io/documents/NVDIMM_DSM_Interface_Example.pdf
+ *
+ * Currently, it only supports PMEM Virtualization.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "hw/mem/nvdimm.h"
+
+static uint64_t
+nvdimm_dsm_read(void *opaque, hwaddr addr, unsigned size)
+{
+    return 0;
+}
+
+static void
+nvdimm_dsm_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
+{
+}
+
+static const MemoryRegionOps nvdimm_dsm_ops = {
+    .read = nvdimm_dsm_read,
+    .write = nvdimm_dsm_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+void nvdimm_init_acpi_state(MemoryRegion *memory, MemoryRegion *io,
+                            Object *owner, AcpiNVDIMMState *state)
+{
+    memory_region_init_ram(&state->ram_mr, owner, "nvdimm-acpi-ram",
+                           TARGET_PAGE_SIZE, &error_abort);
+    vmstate_register_ram_global(&state->ram_mr);
+    memory_region_add_subregion(memory, NVDIMM_ACPI_MEM_BASE, &state->ram_mr);
+
+    memory_region_init_io(&state->io_mr, owner, &nvdimm_dsm_ops, state,
+                          "nvdimm-acpi-io", NVDIMM_ACPI_IO_LEN);
+    memory_region_add_subregion(io, NVDIMM_ACPI_IO_BASE, &state->io_mr);
+}
diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c
index b2f5b2c..39b8415 100644
--- a/hw/acpi/piix4.c
+++ b/hw/acpi/piix4.c
@@ -34,6 +34,7 @@ 
 #include "hw/acpi/cpu_hotplug.h"
 #include "hw/hotplug.h"
 #include "hw/mem/dimm.h"
+#include "hw/mem/nvdimm.h"
 #include "hw/acpi/memory_hotplug.h"
 #include "hw/acpi/acpi_dev_interface.h"
 #include "hw/xen/xen.h"
@@ -86,6 +87,8 @@  typedef struct PIIX4PMState {
     AcpiCpuHotplug gpe_cpu;
 
     MemHotplugState acpi_memory_hotplug;
+
+    AcpiNVDIMMState acpi_nvdimm_state;
 } PIIX4PMState;
 
 #define TYPE_PIIX4_PM "PIIX4_PM"
@@ -93,7 +96,8 @@  typedef struct PIIX4PMState {
 #define PIIX4_PM(obj) \
     OBJECT_CHECK(PIIX4PMState, (obj), TYPE_PIIX4_PM)
 
-static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
+static void piix4_acpi_system_hot_add_init(MemoryRegion *mem_parent,
+                                           MemoryRegion *io_parent,
                                            PCIBus *bus, PIIX4PMState *s);
 
 #define ACPI_ENABLE 0xf1
@@ -486,7 +490,8 @@  static void piix4_pm_realize(PCIDevice *dev, Error **errp)
     qemu_add_machine_init_done_notifier(&s->machine_ready);
     qemu_register_reset(piix4_reset, s);
 
-    piix4_acpi_system_hot_add_init(pci_address_space_io(dev), dev->bus, s);
+    piix4_acpi_system_hot_add_init(pci_address_space(dev),
+                                   pci_address_space_io(dev), dev->bus, s);
 
     piix4_pm_add_propeties(s);
 }
@@ -558,21 +563,27 @@  static const MemoryRegionOps piix4_gpe_ops = {
     .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
-static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
+static void piix4_acpi_system_hot_add_init(MemoryRegion *mem_parent,
+                                           MemoryRegion *io_parent,
                                            PCIBus *bus, PIIX4PMState *s)
 {
     memory_region_init_io(&s->io_gpe, OBJECT(s), &piix4_gpe_ops, s,
                           "acpi-gpe0", GPE_LEN);
-    memory_region_add_subregion(parent, GPE_BASE, &s->io_gpe);
+    memory_region_add_subregion(io_parent, GPE_BASE, &s->io_gpe);
 
-    acpi_pcihp_init(OBJECT(s), &s->acpi_pci_hotplug, bus, parent,
+    acpi_pcihp_init(OBJECT(s), &s->acpi_pci_hotplug, bus, io_parent,
                     s->use_acpi_pci_hotplug);
 
-    acpi_cpu_hotplug_init(parent, OBJECT(s), &s->gpe_cpu,
+    acpi_cpu_hotplug_init(io_parent, OBJECT(s), &s->gpe_cpu,
                           PIIX4_CPU_HOTPLUG_IO_BASE);
 
     if (s->acpi_memory_hotplug.is_enabled) {
-        acpi_memory_hotplug_init(parent, OBJECT(s), &s->acpi_memory_hotplug);
+        acpi_memory_hotplug_init(io_parent, OBJECT(s), &s->acpi_memory_hotplug);
+    }
+
+    if (s->acpi_nvdimm_state.is_enabled) {
+        nvdimm_init_acpi_state(mem_parent, io_parent, OBJECT(s),
+                               &s->acpi_nvdimm_state);
     }
 }
 
@@ -592,6 +603,8 @@  static Property piix4_pm_properties[] = {
                      use_acpi_pci_hotplug, true),
     DEFINE_PROP_BOOL("memory-hotplug-support", PIIX4PMState,
                      acpi_memory_hotplug.is_enabled, true),
+    DEFINE_PROP_BOOL("nvdimm-support", PIIX4PMState,
+                     acpi_nvdimm_state.is_enabled, true),
     DEFINE_PROP_END_OF_LIST(),
 };
 
diff --git a/include/hw/acpi/ich9.h b/include/hw/acpi/ich9.h
index 345fd8d..66a99d4 100644
--- a/include/hw/acpi/ich9.h
+++ b/include/hw/acpi/ich9.h
@@ -26,6 +26,7 @@ 
 #include "hw/acpi/memory_hotplug.h"
 #include "hw/acpi/acpi_dev_interface.h"
 #include "hw/acpi/tco.h"
+#include "hw/mem/nvdimm.h"
 
 typedef struct ICH9LPCPMRegs {
     /*
@@ -52,6 +53,8 @@  typedef struct ICH9LPCPMRegs {
 
     MemHotplugState acpi_memory_hotplug;
 
+    AcpiNVDIMMState acpi_nvdimm_state;
+
     uint8_t disable_s3;
     uint8_t disable_s4;
     uint8_t s4_val;
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 62e8fb5..47162cf 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -322,6 +322,16 @@  bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
             .driver   = "host" "-" TYPE_X86_CPU,\
             .property = "host-cache-info",\
             .value    = "on",\
+        },\
+        {\
+            .driver   = "PIIX4_PM",\
+            .property = "nvdimm-support",\
+            .value    = "off",\
+        },\
+        {\
+            .driver   = "ICH9-LPC",\
+            .property = "nvdimm-support",\
+            .value    = "off",\
         },
 
 #define PC_COMPAT_2_3 \
diff --git a/include/hw/mem/nvdimm.h b/include/hw/mem/nvdimm.h
index cd90957..f0b1dda 100644
--- a/include/hw/mem/nvdimm.h
+++ b/include/hw/mem/nvdimm.h
@@ -33,6 +33,15 @@ 
  */
 #define MIN_NAMESPACE_LABEL_SIZE      (128UL << 10)
 
+/*
+ * A page staring from 0xFF00000 and IO port 0x0a18 - 0xa1b in guest are
+ * reserved for NVDIMM ACPI emulation, refer to docs/specs/acpi_nvdimm.txt
+ * for detailed design.
+ */
+#define NVDIMM_ACPI_MEM_BASE          0xFF000000ULL
+#define NVDIMM_ACPI_IO_BASE           0x0a18
+#define NVDIMM_ACPI_IO_LEN            4
+
 #define TYPE_NVDIMM      "nvdimm"
 #define NVDIMM(obj)      OBJECT_CHECK(NVDIMMDevice, (obj), TYPE_NVDIMM)
 #define NVDIMM_CLASS(oc) OBJECT_CLASS_CHECK(NVDIMMClass, (oc), TYPE_NVDIMM)
@@ -80,4 +89,29 @@  struct NVDIMMClass {
 };
 typedef struct NVDIMMClass NVDIMMClass;
 
+/*
+ * AcpiNVDIMMState:
+ * @is_enabled: detect if NVDIMM support is enabled.
+ *
+ * @fit: fit buffer which will be accessed via ACPI _FIT method. It is
+ *       dynamically built based on current NVDIMM devices so that it does
+ *       not require to keep consistent during live migration.
+ *
+ * @ram_mr: RAM-based memory region which is mapped into guest address
+ *          space and used to transfer data between OSPM and QEMU.
+ * @io_mr: the IO region used by OSPM to transfer control to QEMU.
+ */
+struct AcpiNVDIMMState {
+    bool is_enabled;
+
+    GArray *fit;
+
+    MemoryRegion ram_mr;
+    MemoryRegion io_mr;
+};
+typedef struct AcpiNVDIMMState AcpiNVDIMMState;
+
+/* Initialize the memory and IO region needed by NVDIMM ACPI emulation.*/
+void nvdimm_init_acpi_state(MemoryRegion *memory, MemoryRegion *io,
+                            Object *owner, AcpiNVDIMMState *state);
 #endif