 45a994944a
			
		
	
	
		45a994944a
		
	
	
	
	
		
			
			Improve the description and clearly document the length field Suggested-by: Igor Mammedov <imammedo@redhat.com> Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Reviewed-by: Igor Mammedov <imammedo@redhat.com>
		
			
				
	
	
		
			188 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			188 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| QEMU<->ACPI BIOS NVDIMM interface
 | ||
| ---------------------------------
 | ||
| 
 | ||
| QEMU supports NVDIMM via ACPI. This document describes the basic concepts of
 | ||
| NVDIMM ACPI and the interface between QEMU and the ACPI BIOS.
 | ||
| 
 | ||
| NVDIMM ACPI Background
 | ||
| ----------------------
 | ||
| NVDIMM is introduced in ACPI 6.0 which defines an NVDIMM root device under
 | ||
| _SB scope with a _HID of “ACPI0012”. For each NVDIMM present or intended
 | ||
| to be supported by platform, platform firmware also exposes an ACPI
 | ||
| Namespace Device under the root device.
 | ||
| 
 | ||
| The NVDIMM child devices under the NVDIMM root device are defined with _ADR
 | ||
| corresponding to the NFIT device handle. The NVDIMM root device and the
 | ||
| NVDIMM devices can have device specific methods (_DSM) to provide additional
 | ||
| functions specific to a particular NVDIMM implementation.
 | ||
| 
 | ||
| This is an example from ACPI 6.0, a platform contains one NVDIMM:
 | ||
| 
 | ||
| Scope (\_SB){
 | ||
|    Device (NVDR) // Root device
 | ||
|    {
 | ||
|       Name (_HID, “ACPI0012”)
 | ||
|       Method (_STA) {...}
 | ||
|       Method (_FIT) {...}
 | ||
|       Method (_DSM, ...) {...}
 | ||
|       Device (NVD)
 | ||
|       {
 | ||
|          Name(_ADR, h) //where h is NFIT Device Handle for this NVDIMM
 | ||
|          Method (_DSM, ...) {...}
 | ||
|       }
 | ||
|    }
 | ||
| }
 | ||
| 
 | ||
| Method supported on both NVDIMM root device and NVDIMM device
 | ||
| _DSM (Device Specific Method)
 | ||
|    It is a control method that enables devices to provide device specific
 | ||
|    control functions that are consumed by the device driver.
 | ||
|    The NVDIMM DSM specification can be found at:
 | ||
|         http://pmem.io/documents/NVDIMM_DSM_Interface_Example.pdf
 | ||
| 
 | ||
|    Arguments:
 | ||
|    Arg0 – A Buffer containing a UUID (16 Bytes)
 | ||
|    Arg1 – An Integer containing the Revision ID (4 Bytes)
 | ||
|    Arg2 – An Integer containing the Function Index (4 Bytes)
 | ||
|    Arg3 – A package containing parameters for the function specified by the
 | ||
|           UUID, Revision ID, and Function Index
 | ||
| 
 | ||
|    Return Value:
 | ||
|    If Function Index = 0, a Buffer containing a function index bitfield.
 | ||
|    Otherwise, the return value and type depends on the UUID, revision ID
 | ||
|    and function index which are described in the DSM specification.
 | ||
| 
 | ||
| Methods on NVDIMM ROOT Device
 | ||
| _FIT(Firmware Interface Table)
 | ||
|    It evaluates to a buffer returning data in the format of a series of NFIT
 | ||
|    Type Structure.
 | ||
| 
 | ||
|    Arguments: None
 | ||
| 
 | ||
|    Return Value:
 | ||
|    A Buffer containing a list of NFIT Type structure entries.
 | ||
| 
 | ||
|    The detailed definition of the structure can be found at ACPI 6.0: 5.2.25
 | ||
|    NVDIMM Firmware Interface Table (NFIT).
 | ||
| 
 | ||
| QEMU NVDIMM Implementation
 | ||
| ==========================
 | ||
| QEMU uses 4 bytes IO Port starting from 0x0a18 and a RAM-based memory page
 | ||
| for NVDIMM ACPI.
 | ||
| 
 | ||
| Memory:
 | ||
|    QEMU uses BIOS Linker/loader feature to ask BIOS to allocate a memory
 | ||
|    page and dynamically patch its into a int32 object named "MEMA" in ACPI.
 | ||
| 
 | ||
|    This page is RAM-based and it is used to transfer data between _DSM
 | ||
|    method and QEMU. If ACPI has control, this pages is owned by ACPI which
 | ||
|    writes _DSM input data to it, otherwise, it is owned by QEMU which
 | ||
|    emulates _DSM access and writes the output data to it.
 | ||
| 
 | ||
|    ACPI writes _DSM Input Data (based on the offset in the page):
 | ||
|    [0x0 - 0x3]: 4 bytes, NVDIMM Device Handle.
 | ||
| 
 | ||
|                 The handle is completely QEMU internal thing, the values in
 | ||
|                 range [1, 0xFFFF] indicate nvdimm device. Other values are
 | ||
|                 reserved for other purposes.
 | ||
| 
 | ||
|                 Reserved handles:
 | ||
|                 0 is reserved for nvdimm root device named NVDR.
 | ||
|                 0x10000 is reserved for QEMU internal DSM function called on
 | ||
|                 the root device.
 | ||
| 
 | ||
|    [0x4 - 0x7]: 4 bytes, Revision ID, that is the Arg1 of _DSM method.
 | ||
|    [0x8 - 0xB]: 4 bytes. Function Index, that is the Arg2 of _DSM method.
 | ||
|    [0xC - 0xFFF]: 4084 bytes, the Arg3 of _DSM method.
 | ||
| 
 | ||
|    QEMU Writes Output Data (based on the offset in the page):
 | ||
|    [0x0 - 0x3]: 4 bytes, the length of result
 | ||
|    [0x4 - 0xFFF]: 4092 bytes, the DSM result filled by QEMU
 | ||
| 
 | ||
| IO Port 0x0a18 - 0xa1b:
 | ||
|    ACPI writes the address of the memory page allocated by BIOS to this
 | ||
|    port then QEMU gets the control and fills the result in the memory page.
 | ||
| 
 | ||
|    write Access:
 | ||
|    [0x0a18 - 0xa1b]: 4 bytes, the address of the memory page allocated
 | ||
|                      by BIOS.
 | ||
| 
 | ||
| _DSM process diagram:
 | ||
| ---------------------
 | ||
| "MEMA" indicates the address of memory page allocated by BIOS.
 | ||
| 
 | ||
|  +----------------------+      +-----------------------+
 | ||
|  |    1. OSPM           |      |    2. OSPM            |
 | ||
|  | save _DSM input data |      |  write "MEMA" to      | Exit to QEMU
 | ||
|  | to the page          +----->|  IO port 0x0a18       +------------+
 | ||
|  | indicated by "MEMA"  |      |                       |            |
 | ||
|  +----------------------+      +-----------------------+            |
 | ||
|                                                                     |
 | ||
|                                                                     v
 | ||
|  +-------------   ----+       +-----------+      +------------------+--------+
 | ||
|  |      5 QEMU        |       | 4 QEMU    |      |        3. QEMU            |
 | ||
|  | write _DSM result  |       |  emulate  |      | get _DSM input data from  |
 | ||
|  | to the page        +<------+ _DSM      +<-----+ the page indicated by the |
 | ||
|  |                    |       |           |      | value from the IO port    |
 | ||
|  +--------+-----------+       +-----------+      +---------------------------+
 | ||
|           |
 | ||
|           | Enter Guest
 | ||
|           |
 | ||
|           v
 | ||
|  +--------------------------+      +--------------+
 | ||
|  |     6 OSPM               |      |   7 OSPM     |
 | ||
|  | result size is returned  |      |  _DSM return |
 | ||
|  | by reading  DSM          +----->+              |
 | ||
|  | result from the page     |      |              |
 | ||
|  +--------------------------+      +--------------+
 | ||
| 
 | ||
| NVDIMM hotplug
 | ||
| --------------
 | ||
| ACPI BIOS GPE.4 handler is dedicated for notifying OS about nvdimm device
 | ||
| hot-add event.
 | ||
| 
 | ||
| QEMU internal use only _DSM function
 | ||
| ------------------------------------
 | ||
| 1) Read FIT
 | ||
|    _FIT method uses _DSM method to fetch NFIT structures blob from QEMU
 | ||
|    in 1 page sized increments which are then concatenated and returned
 | ||
|    as _FIT method result.
 | ||
| 
 | ||
|    Input parameters:
 | ||
|    Arg0 – UUID {set to 648B9CF2-CDA1-4312-8AD9-49C4AF32BD62}
 | ||
|    Arg1 – Revision ID (set to 1)
 | ||
|    Arg2 - Function Index, 0x1
 | ||
|    Arg3 - A package containing a buffer whose layout is as follows:
 | ||
| 
 | ||
|    +----------+--------+--------+-------------------------------------------+
 | ||
|    |  Field   | Length | Offset |                 Description               |
 | ||
|    +----------+--------+--------+-------------------------------------------+
 | ||
|    | offset   |   4    |   0    | offset in QEMU's NFIT structures blob to  |
 | ||
|    |          |        |        | read from                                 |
 | ||
|    +----------+--------+--------+-------------------------------------------+
 | ||
| 
 | ||
|    Output layout in the dsm memory page:
 | ||
|    +----------+--------+--------+-------------------------------------------+
 | ||
|    |  Field   | Length | Offset |                 Description               |
 | ||
|    +----------+--------+--------+-------------------------------------------+
 | ||
|    | length   |   4    |   0    | length of entire returned data            |
 | ||
|    |          |        |        | (including this header)                   |
 | ||
|    +----------+-----------------+-------------------------------------------+
 | ||
|    |          |        |        | return status codes                       |
 | ||
|    |          |        |        | 0x0 - success                             |
 | ||
|    |          |        |        | 0x100 - error caused by NFIT update while |
 | ||
|    | status   |   4    |   4    | read by _FIT wasn't completed, other      |
 | ||
|    |          |        |        | codes follow Chapter 3 in DSM Spec Rev1   |
 | ||
|    +----------+-----------------+-------------------------------------------+
 | ||
|    | fit data | Varies |   8    | contains FIT data, this field is present  |
 | ||
|    |          |        |        | if status field is 0;                     |
 | ||
|    +----------+--------+--------+-------------------------------------------+
 | ||
| 
 | ||
|    The FIT offset is maintained by the OSPM itself, current offset plus
 | ||
|    the size of the fit data returned by the function is the next offset
 | ||
|    OSPM should read. When all FIT data has been read out, zero fit data
 | ||
|    size is returned.
 | ||
| 
 | ||
|    If it returns status code 0x100, OSPM should restart to read FIT (read
 | ||
|    from offset 0 again).
 |